mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-02-09 05:24:58 +00:00
Compare commits
364 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 |
@@ -28,4 +28,17 @@ To do:
|
||||
CCExtractor fully support Asian languages. I do need samples
|
||||
though. No samples, no support.
|
||||
- A few commands are not yet supported, specifically those related
|
||||
to delay.
|
||||
to delay.
|
||||
- Detect and extract captions from MP4 (MOV) files, handled by gpacmp4
|
||||
|
||||
Done (18.08.2015):
|
||||
|
||||
- Major refactoring
|
||||
- Librarized as much as possible (global vars moved to dtvcc context)
|
||||
- Added some control commands support
|
||||
- 16 bit charset support added (not "moved everything to 16-bit", but they could be successfully exported)
|
||||
- SAMI output added
|
||||
- Transcript output added
|
||||
- Timed transcript output added
|
||||
- Added colour support (only one colour/style can be applied for the whole screen at the moment)
|
||||
- Roll up captions handling
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
0.78 (2015-12-12)
|
||||
-----------------
|
||||
- Support to extract Closed Caption from MultiProgram at once.
|
||||
- CEA-708: exporting to SAMI (.smi), Transcript (.txt), Timed Transcript (ttxt) and SubRip (.srt).
|
||||
- CEA-708: 16 bit charset support (tested on Korean).
|
||||
- CEA-708: Roll Up captions handling.
|
||||
- Changed TCP connection protocol (BIN data is now wrapped in packets, added EPG support and keep-alive packets).
|
||||
- TCP connection password prompt is removed. To set connection password use -tcppassword argument instead.
|
||||
- Support ISDB Closed Caption.
|
||||
- Added a new output format, simplexml (used internally by a CCExtractor user, may or may not be useful for
|
||||
anyone else).
|
||||
|
||||
0.77 (2015-06-20)
|
||||
-----------------
|
||||
- Fixed bug in capitalization code ('I' was not being capitalized).
|
||||
|
||||
18
docs/OCR.txt
18
docs/OCR.txt
@@ -43,9 +43,10 @@ sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
Note:
|
||||
1) CCExtractor is tested with Tesseract 3.02.02 version.
|
||||
1) CCExtractor is tested with Tesseract 3.04 version but it works with older versions.
|
||||
|
||||
you can download tesseract from https://drive.google.com/folderview?id=0B7l10Bj_LprhQnpSRkpGMGV2eE0&usp=sharing
|
||||
you can download tesseract from https://github.com/tesseract-ocr/tesseract/archive/3.04.00.tar.gz
|
||||
you can download tesseract training data from https://github.com/tesseract-ocr/tessdata/archive/3.04.00.tar.gz
|
||||
|
||||
|
||||
|
||||
@@ -57,11 +58,8 @@ make ENABLE_OCR=yes
|
||||
How to compile ccextractor on Windows with OCR
|
||||
===============================================
|
||||
|
||||
Download prebuild library of leptonica from following link
|
||||
http://www.leptonica.com/source/leptonica-1.68-win32-lib-include-dirs.zip
|
||||
|
||||
Download prebuild library of tesseract from following tesseract official link
|
||||
https://code.google.com/p/tesseract-ocr/downloads/detail?name=tesseract-3.02.02-win32-lib-include-dirs.zip
|
||||
Download prebuild library of leptonica and tesseract from following link
|
||||
https://drive.google.com/file/d/0B2ou7ZfB-2nZOTRtc3hJMHBtUFk/view?usp=sharing
|
||||
|
||||
put the path of libs/include of leptonica and tesseract in library paths.
|
||||
step 1) In visual studio 2013 right click <Project> and select property.
|
||||
@@ -85,12 +83,12 @@ Step 2)Select Configuration properties
|
||||
Step 3)Select Linker in left panel(column)
|
||||
Step 4)Select Input
|
||||
Step 5)Select Additional dependencies in right panel
|
||||
Step 6)Add libtesseract302.lib in new line
|
||||
Step 7)Add liblept168.lib in new line
|
||||
Step 6)Add libtesseract304d.lib in new line
|
||||
Step 7)Add liblept172.lib in new line
|
||||
|
||||
Download language data from following link
|
||||
https://code.google.com/p/tesseract-ocr/downloads/list
|
||||
after downloading the tesseract-ocr-3.02.eng.tar.gz extract the tar file and put
|
||||
tessdata folder where you have kept ccextractor executable
|
||||
|
||||
Copy the tesseract and leptonica dll in the folder of executable or in system32.
|
||||
Copy the tesseract and leptonica dll from lib folder downloaded from above link to folder of executable or in system32.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ccextractor, 0.77
|
||||
ccextractor, 0.78
|
||||
-----------------
|
||||
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
|
||||
Maintainer: cfsmp3
|
||||
@@ -20,7 +20,7 @@ Google Summer of Code 2014 students
|
||||
|
||||
Google Summer of Code 2015 students
|
||||
- Willem van iseghem
|
||||
- Ruslan KuchumoV
|
||||
- Ruslan Kuchumov
|
||||
- Anshul Maheshwari
|
||||
- Nurendra Choudhary
|
||||
- Oleg Kiselev
|
||||
|
||||
@@ -42,7 +42,7 @@ INSTLALL_PROGRAM = $(INSTLALL)
|
||||
DESTDIR = /usr/bin
|
||||
|
||||
ifeq ($(ENABLE_OCR),yes)
|
||||
CFLAGS+=-DENABLE_OCR
|
||||
CFLAGS+=-DENABLE_OCR -DPNG_NO_CONFIG_H
|
||||
TESS_LDFLAGS+= $(shell pkg-config --libs tesseract)
|
||||
LEPT_LDFLAGS+= $(shell pkg-config --libs lept)
|
||||
|
||||
|
||||
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/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
|
||||
BLD_FLAGS="-std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64"
|
||||
BLD_INCLUDE="-I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/"
|
||||
SRC_LIBPNG="$(find ../src/libpng/ -name '*.c')"
|
||||
SRC_ZLIB="$(find ../src/zlib/ -name '*.c')"
|
||||
SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')"
|
||||
SRC_GPAC="$(find ../src/gpacmp4/ -name '*.c')"
|
||||
BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG"
|
||||
BLD_LINKER="-lm -zmuldefs"
|
||||
|
||||
gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER
|
||||
@@ -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
|
||||
@@ -24,15 +24,13 @@ void sigint_handler()
|
||||
struct ccx_s_options ccx_options;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct encoder_ctx enc_ctx[2];
|
||||
struct cc_subtitle dec_sub;
|
||||
#ifdef ENABLE_FFMPEG
|
||||
void *ffmpeg_ctx = NULL;
|
||||
#endif
|
||||
struct lib_ccx_ctx *ctx;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
int ret = 0;
|
||||
|
||||
enum ccx_stream_mode_enum stream_mode;
|
||||
|
||||
init_options (&ccx_options);
|
||||
|
||||
@@ -53,39 +51,15 @@ int main(int argc, char *argv[])
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
else if (!ctx && errno == EINVAL)
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Invalid option to CCextractor Library\n");
|
||||
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
|
||||
|
||||
// Prepare write structures
|
||||
init_write(&ctx->wbout1,ccx_options.wbout1.filename);
|
||||
init_write(&ctx->wbout2,ccx_options.wbout2.filename);
|
||||
|
||||
else if (!ctx && errno == EPERM)
|
||||
fatal (CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to create Output File\n");
|
||||
else if (!ctx && errno == EACCES)
|
||||
fatal (CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to create Output File\n");
|
||||
else if (!ctx)
|
||||
fatal (EXIT_NOT_CLASSIFIED, "Unable to create Library Context %d\n",errno);
|
||||
|
||||
int show_myth_banner = 0;
|
||||
|
||||
memset (&cea708services[0],0,CCX_DECODERS_708_MAX_SERVICES*sizeof (int)); // Cannot (yet) be moved because it's needed in parse_parameters.
|
||||
memset (&dec_sub, 0,sizeof(dec_sub));
|
||||
|
||||
|
||||
if (ctx->num_input_files > 0)
|
||||
{
|
||||
ctx->wbout1.multiple_files = 1;
|
||||
ctx->wbout1.first_input_file = ctx->inputfile[0];
|
||||
ctx->wbout2.multiple_files = 1;
|
||||
ctx->wbout2.first_input_file = ctx->inputfile[0];
|
||||
}
|
||||
|
||||
if (ccx_options.output_filename!=NULL)
|
||||
{
|
||||
// Use the given output file name for the field specified by
|
||||
// the -1, -2 switch. If -12 is used, the filename is used for
|
||||
// field 1.
|
||||
if (ccx_options.extract==2)
|
||||
ctx->wbout2.filename=ccx_options.output_filename;
|
||||
else
|
||||
ctx->wbout1.filename=ccx_options.output_filename;
|
||||
}
|
||||
params_dump(ctx);
|
||||
|
||||
// default teletext page
|
||||
@@ -94,161 +68,6 @@ int main(int argc, char *argv[])
|
||||
tlt_config.page = ((tlt_config.page / 100) << 8) | (((tlt_config.page / 10) % 10) << 4) | (tlt_config.page % 10);
|
||||
}
|
||||
|
||||
if (ctx->auto_stream==CCX_SM_MCPOODLESRAW && ccx_options.write_format==CCX_OF_RAW)
|
||||
{
|
||||
fatal (EXIT_INCOMPATIBLE_PARAMETERS, "-in=raw can only be used if the output is a subtitle file.\n");
|
||||
}
|
||||
if (ctx->auto_stream==CCX_SM_RCWT && ccx_options.write_format==CCX_OF_RCWT && ccx_options.output_filename==NULL)
|
||||
{
|
||||
fatal (EXIT_INCOMPATIBLE_PARAMETERS,
|
||||
"CCExtractor's binary format can only be used simultaneously for input and\noutput if the output file name is specified given with -o.\n");
|
||||
}
|
||||
|
||||
subline = (unsigned char *) malloc (SUBLINESIZE);
|
||||
|
||||
if (ctx->wbout1.filename==NULL)
|
||||
{
|
||||
ctx->wbout1.filename = (char *) malloc (strlen (ctx->basefilename)+3+strlen (ctx->extension));
|
||||
ctx->wbout1.filename[0]=0;
|
||||
}
|
||||
if (ctx->wbout2.filename==NULL)
|
||||
{
|
||||
ctx->wbout2.filename = (char *) malloc (strlen (ctx->basefilename)+3+strlen (ctx->extension));
|
||||
ctx->wbout2.filename[0]=0;
|
||||
}
|
||||
if (ctx->buffer == NULL || ctx->pesheaderbuf==NULL ||
|
||||
ctx->wbout1.filename == NULL || ctx->wbout2.filename == NULL ||
|
||||
subline==NULL || init_file_buffer() )
|
||||
{
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
}
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
{
|
||||
connect_to_srv(ccx_options.srv_addr, ccx_options.srv_port, ccx_options.tcp_desc);
|
||||
}
|
||||
|
||||
if (ccx_options.write_format!=CCX_OF_NULL)
|
||||
{
|
||||
/* # DVD format uses one raw file for both fields, while Broadcast requires 2 */
|
||||
if (ccx_options.write_format==CCX_OF_DVDRAW)
|
||||
{
|
||||
if (ctx->wbout1.filename[0]==0)
|
||||
{
|
||||
strcpy (ctx->wbout1.filename,ctx->basefilename);
|
||||
strcat (ctx->wbout1.filename,".raw");
|
||||
}
|
||||
if (ctx->cc_to_stdout)
|
||||
{
|
||||
ctx->wbout1.fh=STDOUT_FILENO;
|
||||
mprint ("Sending captions to stdout.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
mprint ("Creating %s\n", ctx->wbout1.filename);
|
||||
if (detect_input_file_overwrite(ctx, ctx->wbout1.filename)) {
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED,
|
||||
"Output filename is same as one of input filenames. Check output parameters.\n");
|
||||
}
|
||||
ctx->wbout1.fh=open (ctx->wbout1.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
if (ctx->wbout1.fh==-1)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n");
|
||||
}
|
||||
}
|
||||
if (init_encoder(enc_ctx, &ctx->wbout1, &ccx_options))
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
set_encoder_subs_delay(enc_ctx, ctx->subs_delay);
|
||||
set_encoder_last_displayed_subs_ms(enc_ctx, ctx->last_displayed_subs_ms);
|
||||
set_encoder_startcredits_displayed(enc_ctx, ctx->startcredits_displayed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx->cc_to_stdout && ccx_options.extract==12)
|
||||
fatal (EXIT_INCOMPATIBLE_PARAMETERS, "You can't extract both fields to stdout at the same time in broadcast mode.");
|
||||
|
||||
if (ccx_options.write_format == CCX_OF_SPUPNG && ctx->cc_to_stdout)
|
||||
fatal (EXIT_INCOMPATIBLE_PARAMETERS, "You cannot use -out=spupng with -stdout.");
|
||||
|
||||
if (ccx_options.extract!=2)
|
||||
{
|
||||
if (ctx->cc_to_stdout)
|
||||
{
|
||||
ctx->wbout1.fh=STDOUT_FILENO;
|
||||
mprint ("Sending captions to stdout.\n");
|
||||
}
|
||||
else if (!ccx_options.send_to_srv)
|
||||
{
|
||||
if (ctx->wbout1.filename[0]==0)
|
||||
{
|
||||
strcpy (ctx->wbout1.filename,ctx->basefilename);
|
||||
if (ccx_options.extract==12) // _1 only added if there's two files
|
||||
strcat (ctx->wbout1.filename,"_1");
|
||||
strcat (ctx->wbout1.filename,(const char *) ctx->extension);
|
||||
}
|
||||
mprint ("Creating %s\n", ctx->wbout1.filename);
|
||||
if (detect_input_file_overwrite(ctx, ctx->wbout1.filename)) {
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED,
|
||||
"Output filename is same as one of input filenames. Check output parameters.\n");
|
||||
}
|
||||
ctx->wbout1.fh=open (ctx->wbout1.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
if (ctx->wbout1.fh==-1)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed (errno=%d)\n", errno);
|
||||
}
|
||||
}
|
||||
if (init_encoder(enc_ctx, &ctx->wbout1, &ccx_options))
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
set_encoder_subs_delay(enc_ctx, ctx->subs_delay);
|
||||
set_encoder_last_displayed_subs_ms(enc_ctx, ctx->last_displayed_subs_ms);
|
||||
set_encoder_startcredits_displayed(enc_ctx, ctx->startcredits_displayed);
|
||||
}
|
||||
if (ccx_options.extract == 12 && ccx_options.write_format != CCX_OF_RAW)
|
||||
mprint (" and \n");
|
||||
if (ccx_options.extract!=1)
|
||||
{
|
||||
if (ctx->cc_to_stdout)
|
||||
{
|
||||
ctx->wbout1.fh=STDOUT_FILENO;
|
||||
mprint ("Sending captions to stdout.\n");
|
||||
}
|
||||
else if(ccx_options.write_format == CCX_OF_RAW
|
||||
&& ccx_options.extract == 12)
|
||||
{
|
||||
memcpy(&ctx->wbout2, &ctx->wbout1,sizeof(ctx->wbout1));
|
||||
}
|
||||
else if (!ccx_options.send_to_srv)
|
||||
{
|
||||
if (ctx->wbout2.filename[0]==0)
|
||||
{
|
||||
strcpy (ctx->wbout2.filename,ctx->basefilename);
|
||||
if (ccx_options.extract==12) // _ only added if there's two files
|
||||
strcat (ctx->wbout2.filename,"_2");
|
||||
strcat (ctx->wbout2.filename,(const char *) ctx->extension);
|
||||
}
|
||||
mprint ("Creating %s\n", ctx->wbout2.filename);
|
||||
if (detect_input_file_overwrite(ctx, ctx->wbout2.filename)) {
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED,
|
||||
"Output filename is same as one of input filenames. Check output parameters.\n");
|
||||
}
|
||||
ctx->wbout2.fh=open (ctx->wbout2.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
if (ctx->wbout2.fh==-1)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n");
|
||||
}
|
||||
if(ccx_options.write_format == CCX_OF_RAW)
|
||||
dec_ctx->writedata (BROADCAST_HEADER,sizeof (BROADCAST_HEADER), dec_ctx->context_cc608_field_2, NULL);
|
||||
}
|
||||
|
||||
if( init_encoder(enc_ctx+1, &ctx->wbout2, &ccx_options) )
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
set_encoder_subs_delay(enc_ctx+1, ctx->subs_delay);
|
||||
set_encoder_last_displayed_subs_ms(enc_ctx+1, ctx->last_displayed_subs_ms);
|
||||
set_encoder_startcredits_displayed(enc_ctx+1, ctx->startcredits_displayed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.transcript_settings.xds)
|
||||
{
|
||||
if (ccx_options.write_format != CCX_OF_TRANSCRIPT)
|
||||
@@ -258,34 +77,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.teletext_mode == CCX_TXT_IN_USE) // Here, it would mean it was forced by user
|
||||
telxcc_init(ctx);
|
||||
|
||||
ctx->fh_out_elementarystream = NULL;
|
||||
if (ccx_options.out_elementarystream_filename!=NULL)
|
||||
{
|
||||
if ((ctx->fh_out_elementarystream = fopen (ccx_options.out_elementarystream_filename,"wb"))==NULL)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to open clean file: %s\n", ccx_options.out_elementarystream_filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Initialize HDTV caption buffer
|
||||
init_hdcc();
|
||||
|
||||
if (ccx_options.line_terminator_lf)
|
||||
encoded_crlf_length = encode_line(encoded_crlf, (unsigned char *) "\n");
|
||||
else
|
||||
encoded_crlf_length = encode_line(encoded_crlf, (unsigned char *) "\r\n");
|
||||
|
||||
encoded_br_length = encode_line(encoded_br, (unsigned char *) "<br>");
|
||||
|
||||
|
||||
time_t start, final;
|
||||
time(&start);
|
||||
|
||||
dec_ctx->processed_enough=0;
|
||||
if (ccx_options.binary_concat)
|
||||
{
|
||||
ctx->total_inputsize=gettotalfilessize(ctx);
|
||||
@@ -298,7 +93,7 @@ int main(int argc, char *argv[])
|
||||
m_signal(SIGINT, sigint_handler);
|
||||
#endif
|
||||
|
||||
while (switch_to_next_file(ctx, 0) && !dec_ctx->processed_enough)
|
||||
while (switch_to_next_file(ctx, 0))
|
||||
{
|
||||
prepare_for_new_file(ctx);
|
||||
#ifdef ENABLE_FFMPEG
|
||||
@@ -328,11 +123,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
cc_count = len/3;
|
||||
ret = process_cc_data(dec_ctx, bptr, cc_count, &dec_sub);
|
||||
if(ret >= 0 && dec_sub.got_output)
|
||||
ret = process_cc_data(dec_ctx, bptr, cc_count, &dec_ctx->dec_sub);
|
||||
if(ret >= 0 && dec_ctx->dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
encode_sub(enc_ctx, &dec_ctx->dec_sub);
|
||||
dec_ctx->dec_sub.got_output = 0;
|
||||
}
|
||||
}while(1);
|
||||
continue;
|
||||
@@ -342,105 +137,30 @@ int main(int argc, char *argv[])
|
||||
mprint ("\rFailed to initialized ffmpeg falling back to legacy\n");
|
||||
}
|
||||
#endif
|
||||
if (ctx->auto_stream == CCX_SM_AUTODETECT)
|
||||
{
|
||||
detect_stream_type(ctx);
|
||||
switch (ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
mprint ("\rFile seems to be an elementary stream, enabling ES mode\n");
|
||||
break;
|
||||
case CCX_SM_TRANSPORT:
|
||||
mprint ("\rFile seems to be a transport stream, enabling TS mode\n");
|
||||
break;
|
||||
case CCX_SM_PROGRAM:
|
||||
mprint ("\rFile seems to be a program stream, enabling PS mode\n");
|
||||
break;
|
||||
case CCX_SM_ASF:
|
||||
mprint ("\rFile seems to be an ASF, enabling DVR-MS mode\n");
|
||||
break;
|
||||
case CCX_SM_WTV:
|
||||
mprint ("\rFile seems to be a WTV, enabling WTV mode\n");
|
||||
break;
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
mprint ("\rFile seems to be McPoodle raw data\n");
|
||||
break;
|
||||
case CCX_SM_RCWT:
|
||||
mprint ("\rFile seems to be a raw caption with time data\n");
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
mprint ("\rFile seems to be a MP4\n");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
mprint ("\rFile seems to be an hexadecimal dump\n");
|
||||
break;
|
||||
#endif
|
||||
case CCX_SM_MYTH:
|
||||
case CCX_SM_AUTODETECT:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->stream_mode=ctx->auto_stream;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
MAIN LOOP
|
||||
----------------------------------------------------------------- */
|
||||
|
||||
// The myth loop autodetect will only be used with ES or PS streams
|
||||
switch (ccx_options.auto_myth)
|
||||
{
|
||||
case 0:
|
||||
// Use whatever stream mode says
|
||||
break;
|
||||
case 1:
|
||||
// Force stream mode to myth
|
||||
ctx->stream_mode=CCX_SM_MYTH;
|
||||
break;
|
||||
case 2:
|
||||
// autodetect myth files, but only if it does not conflict with
|
||||
// the current stream mode
|
||||
switch (ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
case CCX_SM_PROGRAM:
|
||||
if ( detect_myth(ctx) )
|
||||
{
|
||||
ctx->stream_mode=CCX_SM_MYTH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Keep stream_mode
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx);
|
||||
// Disable sync check for raw formats - they have the right timeline.
|
||||
// Also true for bin formats, but -nosync might have created a
|
||||
// broken timeline for debug purposes.
|
||||
// Disable too in MP4, specs doesn't say that there can't be a jump
|
||||
switch (ctx->stream_mode)
|
||||
switch (stream_mode)
|
||||
{
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
case CCX_SM_RCWT:
|
||||
case CCX_SM_MP4:
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
case CCX_SM_RCWT:
|
||||
case CCX_SM_MP4:
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
case CCX_SM_HEX_DUMP:
|
||||
#endif
|
||||
ccx_common_timing_settings.disable_sync_check = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
ccx_common_timing_settings.disable_sync_check = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ctx->stream_mode)
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
MAIN LOOP
|
||||
----------------------------------------------------------------- */
|
||||
switch (stream_mode)
|
||||
{
|
||||
struct ccx_s_mp4Cfg mp4_cfg = {ccx_options.mp4vidtrack};
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something
|
||||
ccx_options.use_gop_as_pts = 1; // Force GOP timing for ES
|
||||
@@ -452,25 +172,25 @@ int main(int argc, char *argv[])
|
||||
if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something
|
||||
ccx_options.use_gop_as_pts = 0;
|
||||
mprint ("\rAnalyzing data in general mode\n");
|
||||
general_loop(ctx, &enc_ctx);
|
||||
general_loop(ctx);
|
||||
break;
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
mprint ("\rAnalyzing data in McPoodle raw mode\n");
|
||||
raw_loop(ctx, &enc_ctx);
|
||||
raw_loop(ctx);
|
||||
break;
|
||||
case CCX_SM_RCWT:
|
||||
mprint ("\rAnalyzing data in CCExtractor's binary format\n");
|
||||
rcwt_loop(ctx, &enc_ctx);
|
||||
rcwt_loop(ctx);
|
||||
break;
|
||||
case CCX_SM_MYTH:
|
||||
mprint ("\rAnalyzing data in MythTV mode\n");
|
||||
show_myth_banner = 1;
|
||||
myth_loop(ctx, &enc_ctx);
|
||||
myth_loop(ctx);
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
mprint ("\rAnalyzing data with GPAC (MP4 library)\n");
|
||||
close_input_file(ctx); // No need to have it open. GPAC will do it for us
|
||||
processmp4 (ctx, &mp4_cfg, ctx->inputfile[0],&enc_ctx);
|
||||
processmp4 (ctx, &ctx->mp4_cfg, ctx->inputfile[0]);
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx);
|
||||
break;
|
||||
@@ -485,39 +205,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
mprint("\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "\nTime stamps after last caption block was written:\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "Last time stamps: PTS: %s (%+2dF) ",
|
||||
print_mstime( (LLONG) (sync_pts/(MPEG_CLOCK_FREQ/1000)
|
||||
+frames_since_ref_time*1000.0/current_fps) ),
|
||||
frames_since_ref_time);
|
||||
dbg_print(CCX_DMT_DECODER_608, "GOP: %s \n", print_mstime(gop_time.ms) );
|
||||
|
||||
// Blocks since last PTS/GOP time stamp.
|
||||
dbg_print(CCX_DMT_DECODER_608, "Calc. difference: PTS: %s (%+3lldms incl.) ",
|
||||
print_mstime( (LLONG) ((sync_pts-min_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ fts_offset + frames_since_ref_time*1000.0/current_fps)),
|
||||
fts_offset + (LLONG) (frames_since_ref_time*1000.0/current_fps) );
|
||||
dbg_print(CCX_DMT_DECODER_608, "GOP: %s (%+3dms incl.)\n",
|
||||
print_mstime((LLONG)(gop_time.ms
|
||||
-first_gop_time.ms
|
||||
+get_fts_max()-fts_at_gop_start)),
|
||||
(int)(get_fts_max()-fts_at_gop_start));
|
||||
// When padding is active the CC block time should be within
|
||||
// 1000/29.97 us of the differences.
|
||||
dbg_print(CCX_DMT_DECODER_608, "Max. FTS: %s (without caption blocks since then)\n",
|
||||
print_mstime(get_fts_max()));
|
||||
|
||||
if (ctx->stat_hdtv)
|
||||
{
|
||||
mprint ("\rCC type 0: %d (%s)\n", dec_ctx->cc_stats[0], cc_types[0]);
|
||||
mprint ("CC type 1: %d (%s)\n", dec_ctx->cc_stats[1], cc_types[1]);
|
||||
mprint ("CC type 2: %d (%s)\n", dec_ctx->cc_stats[2], cc_types[2]);
|
||||
mprint ("CC type 3: %d (%s)\n", dec_ctx->cc_stats[3], cc_types[3]);
|
||||
}
|
||||
mprint ("\nTotal frames time: %s (%u frames at %.2ffps)\n",
|
||||
print_mstime( (LLONG)(total_frames_count*1000/current_fps) ),
|
||||
total_frames_count, current_fps);
|
||||
#if 0
|
||||
if (ctx->total_pulldownframes)
|
||||
mprint ("incl. pulldown frames: %s (%u frames at %.2ffps)\n",
|
||||
print_mstime( (LLONG)(ctx->total_pulldownframes*1000/current_fps) ),
|
||||
@@ -537,7 +225,7 @@ int main(int argc, char *argv[])
|
||||
- min_pts/(MPEG_CLOCK_FREQ/1000) + fts_offset ));
|
||||
}
|
||||
// dvr-ms files have invalid GOPs
|
||||
if (gop_time.inited && first_gop_time.inited && ctx->stream_mode != CCX_SM_ASF)
|
||||
if (gop_time.inited && first_gop_time.inited && stream_mode != CCX_SM_ASF)
|
||||
{
|
||||
mprint ("\nInitial GOP time: %s\n",
|
||||
print_mstime(first_gop_time.ms));
|
||||
@@ -577,81 +265,68 @@ int main(int argc, char *argv[])
|
||||
mprint("caption is not well understood!\n\n");
|
||||
mprint("Please submit samples to the developers.\n\n\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add one frame as fts_max marks the beginning of the last frame,
|
||||
// but we need the end.
|
||||
fts_global += fts_max + (LLONG) (1000.0/current_fps);
|
||||
// CFS: At least in Hauppage mode, cb_field can be responsible for ALL the
|
||||
// timing (cb_fields having a huge number and fts_now and fts_global being 0 all
|
||||
// the time), so we need to take that into account in fts_global before resetting
|
||||
// counters.
|
||||
if (cb_field1!=0)
|
||||
fts_global += cb_field1*1001/3;
|
||||
else
|
||||
fts_global += cb_field2*1001/3;
|
||||
// Reset counters - This is needed if some captions are still buffered
|
||||
// and need to be written after the last file is processed.
|
||||
cb_field1 = 0; cb_field2 = 0; cb_708 = 0;
|
||||
fts_now = 0;
|
||||
fts_max = 0;
|
||||
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
|
||||
{
|
||||
mprint("\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "\nTime stamps after last caption block was written:\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "GOP: %s \n", print_mstime(gop_time.ms) );
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "GOP: %s (%+3dms incl.)\n",
|
||||
print_mstime((LLONG)(gop_time.ms
|
||||
-first_gop_time.ms
|
||||
+get_fts_max(dec_ctx->timing)-fts_at_gop_start)),
|
||||
(int)(get_fts_max(dec_ctx->timing)-fts_at_gop_start));
|
||||
// When padding is active the CC block time should be within
|
||||
// 1000/29.97 us of the differences.
|
||||
dbg_print(CCX_DMT_DECODER_608, "Max. FTS: %s (without caption blocks since then)\n",
|
||||
print_mstime(get_fts_max(dec_ctx->timing)));
|
||||
|
||||
mprint ("\nTotal frames time: %s (%u frames at %.2ffps)\n",
|
||||
print_mstime( (LLONG)(total_frames_count*1000/current_fps) ),
|
||||
total_frames_count, current_fps);
|
||||
|
||||
if (ctx->stat_hdtv)
|
||||
{
|
||||
mprint ("\rCC type 0: %d (%s)\n", dec_ctx->cc_stats[0], cc_types[0]);
|
||||
mprint ("CC type 1: %d (%s)\n", dec_ctx->cc_stats[1], cc_types[1]);
|
||||
mprint ("CC type 2: %d (%s)\n", dec_ctx->cc_stats[2], cc_types[2]);
|
||||
mprint ("CC type 3: %d (%s)\n", dec_ctx->cc_stats[3], cc_types[3]);
|
||||
}
|
||||
// Add one frame as fts_max marks the beginning of the last frame,
|
||||
// but we need the end.
|
||||
dec_ctx->timing->fts_global += dec_ctx->timing->fts_max + (LLONG) (1000.0/current_fps);
|
||||
// CFS: At least in Hauppage mode, cb_field can be responsible for ALL the
|
||||
// timing (cb_fields having a huge number and fts_now and fts_global being 0 all
|
||||
// the time), so we need to take that into account in fts_global before resetting
|
||||
// counters.
|
||||
if (cb_field1!=0)
|
||||
dec_ctx->timing->fts_global += cb_field1*1001/3;
|
||||
else if (cb_field2!=0)
|
||||
dec_ctx->timing->fts_global += cb_field2*1001/3;
|
||||
else
|
||||
dec_ctx->timing->fts_global += cb_708*1001/3;
|
||||
// Reset counters - This is needed if some captions are still buffered
|
||||
// and need to be written after the last file is processed.
|
||||
cb_field1 = 0; cb_field2 = 0; cb_708 = 0;
|
||||
dec_ctx->timing->fts_now = 0;
|
||||
dec_ctx->timing->fts_max = 0;
|
||||
}
|
||||
|
||||
if(is_decoder_processed_enough(ctx) == CCX_TRUE)
|
||||
break;
|
||||
} // file loop
|
||||
close_input_file(ctx);
|
||||
|
||||
if (ctx->fh_out_elementarystream!=NULL)
|
||||
fclose (ctx->fh_out_elementarystream);
|
||||
|
||||
flushbuffer (ctx, &ctx->wbout1, false);
|
||||
flushbuffer (ctx, &ctx->wbout2, false);
|
||||
|
||||
prepare_for_new_file (ctx); // To reset counters used by handle_end_of_data()
|
||||
|
||||
telxcc_close(ctx);
|
||||
if (ctx->wbout1.fh!=-1)
|
||||
{
|
||||
if (ccx_options.write_format==CCX_OF_SMPTETT || ccx_options.write_format==CCX_OF_SAMI ||
|
||||
ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT
|
||||
|| ccx_options.write_format==CCX_OF_SPUPNG )
|
||||
{
|
||||
handle_end_of_data(dec_ctx->context_cc608_field_1, &dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
else if(ccx_options.write_format==CCX_OF_RCWT)
|
||||
{
|
||||
// Write last header and data
|
||||
writercwtdata (dec_ctx, NULL, &dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
dinit_encoder(enc_ctx);
|
||||
}
|
||||
if (ctx->wbout2.fh!=-1)
|
||||
{
|
||||
if (ccx_options.write_format == CCX_OF_SMPTETT || ccx_options.write_format == CCX_OF_SAMI ||
|
||||
ccx_options.write_format == CCX_OF_SRT || ccx_options.write_format == CCX_OF_TRANSCRIPT
|
||||
|| ccx_options.write_format == CCX_OF_SPUPNG )
|
||||
{
|
||||
handle_end_of_data(dec_ctx->context_cc608_field_2, &dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
}
|
||||
dinit_encoder(enc_ctx+1);
|
||||
}
|
||||
flushbuffer (ctx, &ctx->wbout1,true);
|
||||
flushbuffer (ctx, &ctx->wbout2,true);
|
||||
|
||||
time (&final);
|
||||
|
||||
long proc_time=(long) (final-start);
|
||||
mprint ("\rDone, processing time = %ld seconds\n", proc_time);
|
||||
#if 0
|
||||
if (proc_time>0)
|
||||
{
|
||||
LLONG ratio=(get_fts_max()/10)/proc_time;
|
||||
@@ -660,21 +335,17 @@ int main(int argc, char *argv[])
|
||||
mprint ("Performance (real length/process time) = %u.%02u\n",
|
||||
s1, s2);
|
||||
}
|
||||
dbg_print(CCX_DMT_708, "The 708 decoder was reset [%d] times.\n",resets_708);
|
||||
#endif
|
||||
dbg_print(CCX_DMT_708, "[CEA-708] The 708 decoder was reset [%d] times.\n", ctx->freport.data_from_708->reset_count);
|
||||
/*
|
||||
if (ccx_options.teletext_mode == CCX_TXT_IN_USE)
|
||||
mprint ( "Teletext decoder: %"PRIu32" packets processed, %"PRIu32" SRT frames written.\n", tlt_packet_counter, tlt_frames_produced);
|
||||
|
||||
if (dec_ctx->processed_enough)
|
||||
*/
|
||||
if (is_decoder_processed_enough(ctx) == CCX_TRUE)
|
||||
{
|
||||
mprint ("\rNote: Processing was cancelled before all data was processed because\n");
|
||||
mprint ("\rone or more user-defined limits were reached.\n");
|
||||
}
|
||||
if (ccblocks_in_avc_lost>0)
|
||||
{
|
||||
mprint ("Total caption blocks received: %d\n", ccblocks_in_avc_total);
|
||||
mprint ("Total caption blocks lost: %d\n", ccblocks_in_avc_lost);
|
||||
}
|
||||
|
||||
mprint ("This is beta software. Report issues to carlos at ccextractor org...\n");
|
||||
if (show_myth_banner)
|
||||
{
|
||||
|
||||
@@ -6159,6 +6159,12 @@ static void gf_isom_check_sample_desc(GF_TrackBox *trak)
|
||||
u32 i;
|
||||
|
||||
i=0;
|
||||
if(!trak->Media->information->sampleTable->SampleDescription)
|
||||
{
|
||||
printf("\nCCEXTRACTOR: Ignore table without description\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while ((a = (GF_UnknownBox*)gf_list_enum(trak->Media->information->sampleTable->SampleDescription->boxList, &i))) {
|
||||
switch (a->type) {
|
||||
case GF_ISOM_BOX_TYPE_MP4S:
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_mp4.h"
|
||||
|
||||
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub);
|
||||
void set_fts(void); // From timing.c
|
||||
#include "activity.h"
|
||||
#include "ccx_dtvcc.h"
|
||||
|
||||
static short bswap16(short v)
|
||||
{
|
||||
@@ -33,11 +32,12 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf
|
||||
int status = 0;
|
||||
u32 i;
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
|
||||
set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
|
||||
set_fts(dec_ctx->timing);
|
||||
|
||||
for(i = 0; i < s->dataLength; )
|
||||
{
|
||||
@@ -63,7 +63,7 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf
|
||||
temp_debug=0;
|
||||
|
||||
if (nal_length>0)
|
||||
do_NAL (ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
|
||||
do_NAL (dec_ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
|
||||
i += nal_length;
|
||||
} // outer for
|
||||
assert(i == s->dataLength);
|
||||
@@ -73,8 +73,11 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf
|
||||
static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count;
|
||||
|
||||
int status;
|
||||
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
|
||||
{
|
||||
return 0;
|
||||
@@ -92,24 +95,22 @@ static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_
|
||||
if (s!=NULL)
|
||||
{
|
||||
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
|
||||
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
|
||||
set_fts(dec_ctx->timing);
|
||||
|
||||
process_m2v (ctx, (unsigned char *) s->data,s->dataLength, sub);
|
||||
process_m2v (dec_ctx, (unsigned char *) s->data,s->dataLength, sub);
|
||||
gf_isom_sample_del(&s);
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress(100, cur_sec/60, cur_sec%60);
|
||||
|
||||
return status;
|
||||
@@ -120,6 +121,9 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I
|
||||
u32 timescale, i, sample_count, last_sdi = 0;
|
||||
int status;
|
||||
GF_AVCConfig* c = NULL;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
|
||||
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
|
||||
{
|
||||
@@ -169,12 +173,12 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress(100, cur_sec/60, cur_sec%60);
|
||||
|
||||
if(c != NULL)
|
||||
@@ -280,11 +284,15 @@ unsigned char * ccdp_find_data(unsigned char * ccdp_atom_content, unsigned int l
|
||||
}
|
||||
|
||||
*/
|
||||
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,void *enc_ctx)
|
||||
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file)
|
||||
{
|
||||
GF_ISOFile* f;
|
||||
u32 i, j, track_count, avc_track_count, cc_track_count;
|
||||
struct cc_subtitle dec_sub;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
|
||||
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
|
||||
memset(&dec_sub,0,sizeof(dec_sub));
|
||||
mprint("opening \'%s\': ", file);
|
||||
@@ -344,7 +352,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
}
|
||||
|
||||
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
|
||||
{
|
||||
{
|
||||
if (cc_track_count && !cfg->mp4vidtrack)
|
||||
continue;
|
||||
GF_AVCConfig *cnf = gf_isom_avc_config_get(f,i+1,1);
|
||||
@@ -353,7 +361,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
|
||||
{
|
||||
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
|
||||
do_NAL (ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
|
||||
do_NAL (dec_ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,8 +375,6 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (type == GF_ISOM_MEDIA_CAPTIONS &&
|
||||
(subtype == GF_ISOM_SUBTYPE_C608 || subtype == GF_ISOM_SUBTYPE_C708))
|
||||
@@ -408,10 +414,8 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
mprint ("Data length: %lu\n",sample->dataLength);
|
||||
const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale;
|
||||
#endif
|
||||
current_pts=(LLONG )(sample->DTS + sample->CTS_Offset)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
set_current_pts(dec_ctx->timing, (sample->DTS + sample->CTS_Offset)*MPEG_CLOCK_FREQ/timescale);
|
||||
set_fts(dec_ctx->timing);
|
||||
|
||||
int atomStart = 0;
|
||||
// process Atom by Atom
|
||||
@@ -452,7 +456,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
break;
|
||||
}
|
||||
|
||||
do_cea708 = 1;
|
||||
ctx->dec_global_setting->settings_dtvcc->enabled = 1;
|
||||
unsigned char temp[4];
|
||||
for (int cc_i = 0; cc_i < cc_count; cc_i++, cc_data += 3)
|
||||
{
|
||||
@@ -483,7 +487,9 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708: atom skipped (cc_type < 2)\n");
|
||||
continue;
|
||||
}
|
||||
do_708(ctx->dec_ctx, (unsigned char *) temp, 4);
|
||||
dec_ctx->dtvcc->encoder = (void *)enc_ctx; //WARN: otherwise cea-708 will not work
|
||||
//TODO is it really always 4-bytes long?
|
||||
ccx_dtvcc_process_data(dec_ctx, (unsigned char *) temp, 4);
|
||||
cb_708++;
|
||||
}
|
||||
atomStart = sample->dataLength;
|
||||
@@ -503,7 +509,7 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
data += 4;
|
||||
|
||||
do {
|
||||
ret = process608((unsigned char *) data, len, ctx->dec_ctx->context_cc608_field_1,
|
||||
ret = process608((unsigned char *) data, len, dec_ctx,
|
||||
&dec_sub);
|
||||
len -= ret;
|
||||
data += ret;
|
||||
@@ -521,12 +527,12 @@ int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,voi
|
||||
int progress = (int) ((k*100) / num_samples);
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress(100, cur_sec/60, cur_sec%60);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ endif (WITH_OCR)
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
|
||||
aux_source_directory ("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
|
||||
|
||||
add_library (ccx ${SOURCEFILE})
|
||||
add_library (ccx ${SOURCEFILE} ccx_dtvcc.h ccx_dtvcc.c)
|
||||
|
||||
if (MINGW OR CYGWIN)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGPAC_CONFIG_WIN32")
|
||||
|
||||
17
src/lib_ccx/activity.h
Normal file
17
src/lib_ccx/activity.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ACTIVITY_H
|
||||
#define ACTIVITY_H
|
||||
|
||||
extern unsigned long net_activity_gui;
|
||||
void activity_header (void);
|
||||
void activity_progress (int percentaje, int cur_min, int cur_sec);
|
||||
void activity_report_version (void);
|
||||
void activity_input_file_closed (void);
|
||||
void activity_input_file_open (const char *filename);
|
||||
void activity_message (const char *fmt, ...);
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate);
|
||||
void activity_program_number (unsigned program_number);
|
||||
void activity_library_process(enum ccx_common_logging_gui message_type, ...);
|
||||
void activity_report_data_read (void);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "asf_constants.h"
|
||||
#include "activity.h"
|
||||
#include "file_buffer.h"
|
||||
|
||||
// Indicate first / subsequent calls to asf_getmoredata()
|
||||
int firstcall;
|
||||
@@ -61,7 +63,7 @@ char *guidstr(void *val)
|
||||
* When the function is called the next time it continues to read
|
||||
* where it stopped before, static variables make sure that parameters
|
||||
* are remembered between calls. */
|
||||
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
int asf_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata)
|
||||
{
|
||||
int enough = 0;
|
||||
int payload_read = 0;
|
||||
@@ -98,6 +100,15 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
|
||||
unsigned char *curpos;
|
||||
int64_t getbytes;
|
||||
size_t result = 0;
|
||||
struct demuxer_data *data;
|
||||
|
||||
if(!*ppdata)
|
||||
*ppdata = alloc_demuxer_data();
|
||||
if(!*ppdata)
|
||||
return -1;
|
||||
|
||||
data = *ppdata;
|
||||
|
||||
// Read Header Object and the Top-level Data Object header only once
|
||||
if(firstcall)
|
||||
@@ -152,8 +163,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
asf_data_container.PayloadExtPTSEntry[stream] = -1;
|
||||
}
|
||||
|
||||
buffered_read(ctx, asf_data_container.parsebuf,30);
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, 30);
|
||||
ctx->demux_ctx->past += result;
|
||||
if (result!=30)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -186,8 +197,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
curpos = asf_data_container.parsebuf + 30;
|
||||
getbytes = asf_data_container.HeaderObjectSize - 30;
|
||||
|
||||
buffered_read(ctx, curpos, (int) getbytes);
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, curpos, (int) getbytes);
|
||||
ctx->demux_ctx->past += result;
|
||||
if (result!=getbytes)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -497,7 +508,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
// it is not reliable.
|
||||
|
||||
// Now decide where we are going to expect the captions
|
||||
ccx_bufferdatatype = CCX_PES; // Except for NTSC captions
|
||||
data->bufferdatatype = CCX_PES; // Except for NTSC captions
|
||||
if (asf_data_container.StreamProperties.CaptionStreamNumber > 0
|
||||
&& (asf_data_container.StreamProperties.CaptionStreamStyle == 1 ||
|
||||
(asf_data_container.StreamProperties.CaptionStreamStyle == 2 && !ccx_options.wtvconvertfix)))
|
||||
@@ -510,7 +521,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
//if (debug_parse)
|
||||
mprint("\nNTSC captions in stream #%d\n\n", asf_data_container.StreamProperties.CaptionStreamNumber);
|
||||
ccx_bufferdatatype = CCX_RAW;
|
||||
data->bufferdatatype = CCX_RAW;
|
||||
asf_data_container.StreamProperties.DecodeStreamNumber = asf_data_container.StreamProperties.CaptionStreamNumber;
|
||||
}
|
||||
else if (asf_data_container.StreamProperties.CaptionStreamNumber > 0 && asf_data_container.StreamProperties.CaptionStreamStyle == 2)
|
||||
@@ -535,8 +546,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
asf_data_container.PacketSize = MinPacketSize;
|
||||
|
||||
// Now the Data Object, except for the packages
|
||||
buffered_read(ctx, asf_data_container.parsebuf, 50); // No realloc needed.
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, 50); // No realloc needed.
|
||||
ctx->demux_ctx->past += result;
|
||||
if (result!=50)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -577,8 +588,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
dbg_print(CCX_DMT_PARSE, "\nReading packet %d/%d\n", asf_data_container.datapacketcur + 1, asf_data_container.TotalDataPackets);
|
||||
|
||||
// First packet
|
||||
buffered_read(ctx, asf_data_container.parsebuf, 1); // No realloc needed.
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, 1); // No realloc needed.
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=1)
|
||||
{
|
||||
@@ -594,8 +605,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
fatal(EXIT_NOT_CLASSIFIED, "Error Correction Length Type not 00 - reserved - aborting ...\n");
|
||||
}
|
||||
buffered_read(ctx, asf_data_container.parsebuf + 1, ecdatalength);
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf + 1, ecdatalength);
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=ecdatalength)
|
||||
{
|
||||
@@ -615,8 +626,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
}
|
||||
|
||||
// Now payload parsing information
|
||||
buffered_read(ctx, asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=2)
|
||||
{
|
||||
@@ -651,8 +662,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
|
||||
payloadparsersize = asf_data_container.PacketLType + SequenceType + PaddingLType + 6;
|
||||
|
||||
buffered_read(ctx, asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=payloadparsersize)
|
||||
{
|
||||
@@ -689,8 +700,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned char plheader[1];
|
||||
|
||||
buffered_read(ctx, plheader, 1);
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, plheader, 1);
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=1)
|
||||
{
|
||||
@@ -728,8 +739,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
|
||||
int payloadheadersize = 1 + asf_data_container.MediaNumberLType + asf_data_container.OffsetMediaLType + asf_data_container.ReplicatedLType;
|
||||
|
||||
buffered_read(ctx, asf_data_container.parsebuf, payloadheadersize); // No realloc needed
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, payloadheadersize); // No realloc needed
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=payloadheadersize)
|
||||
{
|
||||
@@ -756,8 +767,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
asf_data_container.parsebufsize = ReplicatedLength;
|
||||
}
|
||||
buffered_read(ctx, asf_data_container.parsebuf, (long)ReplicatedLength);
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, asf_data_container.parsebuf, (long)ReplicatedLength);
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=ReplicatedLength)
|
||||
{
|
||||
@@ -832,8 +843,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned char plheader[4];
|
||||
|
||||
buffered_read(ctx, plheader, asf_data_container.PayloadLType);
|
||||
ctx->past+=result;
|
||||
result = buffered_read(ctx->demux_ctx, plheader, asf_data_container.PayloadLType);
|
||||
ctx->demux_ctx->past += result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result != asf_data_container.PayloadLType)
|
||||
{
|
||||
@@ -927,9 +938,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
}
|
||||
|
||||
// Remember, we are reading the previous package.
|
||||
current_pts = asf_data_container.StreamProperties.currDecodeStreamPTS*(MPEG_CLOCK_FREQ / 1000);
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
data->pts = asf_data_container.StreamProperties.currDecodeStreamPTS*(MPEG_CLOCK_FREQ / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,14 +980,18 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
// Read the data
|
||||
dbg_print(CCX_DMT_PARSE, "Reading Stream #%d data ...\n", asf_data_container.PayloadStreamNumber);
|
||||
|
||||
int want = (long)((BUFSIZE - inbuf)>asf_data_container.PayloadLength ?
|
||||
asf_data_container.PayloadLength : (BUFSIZE - inbuf));
|
||||
data->stream_pid = asf_data_container.StreamProperties.DecodeStreamNumber;
|
||||
data->program_number = 1;
|
||||
data->codec = CCX_CODEC_ATSC_CC;
|
||||
|
||||
int want = (long)((BUFSIZE - data->len)>asf_data_container.PayloadLength ?
|
||||
asf_data_container.PayloadLength : (BUFSIZE - data->len));
|
||||
if (want < (long)asf_data_container.PayloadLength)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Buffer size to small for ASF payload!\nPlease file a bug report!\n");
|
||||
buffered_read (ctx, ctx->buffer+inbuf,want);
|
||||
payload_read+=(int) result;
|
||||
inbuf+=result;
|
||||
ctx->past+=result;
|
||||
result = buffered_read (ctx->demux_ctx, data->buffer+data->len,want);
|
||||
payload_read += (int) result;
|
||||
data->len += result;
|
||||
ctx->demux_ctx->past+=result;
|
||||
if (result != asf_data_container.PayloadLength)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -991,8 +1004,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
// Skip non-cc data
|
||||
dbg_print(CCX_DMT_PARSE, "Skipping Stream #%d data ...\n", asf_data_container.PayloadStreamNumber);
|
||||
buffered_skip(ctx, (int)asf_data_container.PayloadLength);
|
||||
ctx->past+=result;
|
||||
result = buffered_skip(ctx->demux_ctx, (int)asf_data_container.PayloadLength);
|
||||
ctx->demux_ctx->past += result;
|
||||
if (result != asf_data_container.PayloadLength)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -1009,8 +1022,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
|
||||
// Skip padding bytes
|
||||
dbg_print(CCX_DMT_PARSE, "Skip %d padding\n", asf_data_container.PaddingLength);
|
||||
buffered_skip(ctx, (long)asf_data_container.PaddingLength);
|
||||
ctx->past+=result;
|
||||
result = buffered_skip(ctx->demux_ctx, (long)asf_data_container.PaddingLength);
|
||||
ctx->demux_ctx->past += result;
|
||||
if (result != asf_data_container.PaddingLength)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -1029,8 +1042,8 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
|
||||
// Skip the rest of the file
|
||||
dbg_print(CCX_DMT_PARSE, "Skip the rest: %d\n", (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
|
||||
buffered_skip(ctx, (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
|
||||
ctx->past+=result;
|
||||
result = buffered_skip(ctx->demux_ctx, (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
|
||||
ctx->demux_ctx->past += result;
|
||||
// Don not set end_of_file (although it is true) as this would
|
||||
// produce an premature end error.
|
||||
//end_of_file=1;
|
||||
@@ -1038,5 +1051,7 @@ LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
// parsebuf is freed automatically when the program closes.
|
||||
}
|
||||
|
||||
if(!payload_read)
|
||||
return CCX_EOF;
|
||||
return payload_read;
|
||||
}
|
||||
|
||||
@@ -2,59 +2,96 @@
|
||||
#include "ccx_common_option.h"
|
||||
#include "utility.h"
|
||||
#include <math.h>
|
||||
#include "avc_functions.h"
|
||||
|
||||
#define dvprint(...) dbg_print( CCX_DMT_VIDES, __VA_ARGS__)
|
||||
// Functions to parse a AVC/H.264 data stream, see ISO/IEC 14496-10
|
||||
|
||||
int ccblocks_in_avc_total=0;
|
||||
int ccblocks_in_avc_lost=0;
|
||||
|
||||
// local functions
|
||||
static unsigned char *remove_03emu(unsigned char *from, unsigned char *to);
|
||||
static void sei_rbsp (unsigned char *seibuf, unsigned char *seiend);
|
||||
static unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend);
|
||||
static void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *userend);
|
||||
static void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend);
|
||||
static void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
|
||||
|
||||
static unsigned char cc_count;
|
||||
// buffer to hold cc data
|
||||
static unsigned char *cc_data = NULL;
|
||||
static long cc_databufsize = 1024;
|
||||
int cc_buffer_saved=1; // Was the CC buffer saved after it was last updated?
|
||||
|
||||
static int got_seq_para=0;
|
||||
static unsigned nal_ref_idc;
|
||||
static LLONG seq_parameter_set_id;
|
||||
static int log2_max_frame_num=0;
|
||||
static int pic_order_cnt_type;
|
||||
static int log2_max_pic_order_cnt_lsb=0;
|
||||
static int frame_mbs_only_flag;
|
||||
|
||||
// Use and throw stats for debug, remove this uglyness soon
|
||||
long num_nal_unit_type_7=0;
|
||||
long num_vcl_hrd=0;
|
||||
long num_nal_hrd=0;
|
||||
long num_jump_in_frames=0;
|
||||
long num_unexpected_sei_length=0;
|
||||
static void sei_rbsp (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend);
|
||||
static unsigned char *sei_message (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend);
|
||||
static void user_data_registered_itu_t_t35 (struct avc_ctx *ctx, unsigned char *userbuf, unsigned char *userend);
|
||||
static void seq_parameter_set_rbsp (struct avc_ctx *ctx, unsigned char *seqbuf, unsigned char *seqend);
|
||||
static void slice_header (struct lib_cc_decode *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
|
||||
|
||||
double roundportable(double x) { return floor(x + 0.5); }
|
||||
|
||||
int ebsp_to_rbsp(char* rbsp, char* ebsp, int length);
|
||||
|
||||
void init_avc(void)
|
||||
void dinit_avc(struct avc_ctx **ctx)
|
||||
{
|
||||
cc_data = (unsigned char*)malloc(1024);
|
||||
struct avc_ctx *lctx = *ctx;
|
||||
if (lctx->ccblocks_in_avc_lost>0)
|
||||
{
|
||||
mprint ("Total caption blocks received: %d\n", lctx->ccblocks_in_avc_total);
|
||||
mprint ("Total caption blocks lost: %d\n", lctx->ccblocks_in_avc_lost);
|
||||
}
|
||||
freep(&lctx->cc_data);
|
||||
freep(ctx);
|
||||
}
|
||||
|
||||
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
struct avc_ctx *init_avc(void)
|
||||
{
|
||||
struct avc_ctx *ctx = malloc(sizeof(struct avc_ctx ));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->cc_data = (unsigned char*)malloc(1024);
|
||||
if(!ctx->cc_data)
|
||||
{
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->cc_count = 0;
|
||||
// buffer to hold cc data
|
||||
ctx->cc_databufsize = 1024;
|
||||
ctx->cc_buffer_saved = CCX_TRUE; // Was the CC buffer saved after it was last updated?
|
||||
|
||||
ctx->got_seq_para = 0;
|
||||
ctx->nal_ref_idc = 0;
|
||||
ctx->seq_parameter_set_id = 0;
|
||||
ctx->log2_max_frame_num = 0;
|
||||
ctx->pic_order_cnt_type = 0;
|
||||
ctx->log2_max_pic_order_cnt_lsb = 0;
|
||||
ctx->frame_mbs_only_flag = 0;
|
||||
|
||||
ctx->ccblocks_in_avc_total = 0;
|
||||
ctx->ccblocks_in_avc_lost = 0;
|
||||
ctx->frame_num = -1;
|
||||
ctx->lastframe_num = -1;
|
||||
|
||||
ctx->currref = 0;
|
||||
ctx->maxidx = -1;
|
||||
ctx->lastmaxidx=-1;
|
||||
|
||||
// Used to find tref zero in PTS mode
|
||||
ctx->minidx=10000;
|
||||
ctx->lastminidx=10000;
|
||||
|
||||
// Used to remember the max temporal reference number (poc mode)
|
||||
ctx->maxtref = 0;
|
||||
ctx->last_gop_maxtref = 0;
|
||||
|
||||
// Used for PTS ordering of CC blocks
|
||||
ctx->currefpts = 0;
|
||||
|
||||
ctx->last_pic_order_cnt_lsb = -1;
|
||||
ctx->last_slice_pts = -1;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void do_NAL (struct lib_cc_decode *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char *NALstop;
|
||||
unsigned nal_unit_type = *NALstart & 0x1F;
|
||||
enum ccx_avc_nal_types nal_unit_type = *NALstart & 0x1F;
|
||||
|
||||
NALstop = NAL_length+NALstart;
|
||||
NALstop = remove_03emu(NALstart+1, NALstop); // Add +1 to NALstop for TS, without it for MP4. Still don't know why
|
||||
|
||||
dvprint("BEGIN NAL unit type: %d length %d ref_idc: %d - Buffered captions before: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, ctx->avc_ctx->nal_ref_idc, !ctx->avc_ctx->cc_buffer_saved);
|
||||
|
||||
if (NALstop==NULL) // remove_03emu failed.
|
||||
{
|
||||
mprint ("\rNotice: NAL of type %u had to be skipped because remove_03emu failed.\n", nal_unit_type);
|
||||
@@ -69,11 +106,11 @@ void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length,
|
||||
{
|
||||
// Found sequence parameter set
|
||||
// We need this to parse NAL type 1 (CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1)
|
||||
num_nal_unit_type_7++;
|
||||
seq_parameter_set_rbsp(NALstart+1, NALstop);
|
||||
got_seq_para = 1;
|
||||
ctx->avc_ctx->num_nal_unit_type_7++;
|
||||
seq_parameter_set_rbsp(ctx->avc_ctx, NALstart+1, NALstop);
|
||||
ctx->avc_ctx->got_seq_para = 1;
|
||||
}
|
||||
else if ( got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
|
||||
else if ( ctx->avc_ctx->got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
|
||||
nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_IDR_PICTURE)) // Only if nal_unit_type=1
|
||||
{
|
||||
// Found coded slice of a non-IDR picture
|
||||
@@ -81,13 +118,13 @@ void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length,
|
||||
// slice_layer_without_partitioning_rbsp( );
|
||||
slice_header(ctx, NALstart+1, NALstop, nal_unit_type, sub);
|
||||
}
|
||||
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
|
||||
else if ( ctx->avc_ctx->got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
|
||||
{
|
||||
// Found SEI (used for subtitles)
|
||||
//set_fts(); // FIXME - check this!!!
|
||||
sei_rbsp(NALstart+1, NALstop);
|
||||
//set_fts(ctx->timing); // FIXME - check this!!!
|
||||
sei_rbsp(ctx->avc_ctx, NALstart+1, NALstop);
|
||||
}
|
||||
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_PICTURE_PARAMETER_SET )
|
||||
else if ( ctx->avc_ctx->got_seq_para && nal_unit_type == CCX_NAL_TYPE_PICTURE_PARAMETER_SET )
|
||||
{
|
||||
// Found Picture parameter set
|
||||
}
|
||||
@@ -98,11 +135,14 @@ void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length,
|
||||
dump (CCX_DMT_GENERIC_NOTICES,NALstart+1, NALstop-(NALstart+1),0, 0);
|
||||
}
|
||||
|
||||
dvprint("END NAL unit type: %d length %d ref_idc: %d - Buffered captions after: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, ctx->avc_ctx->nal_ref_idc, !ctx->avc_ctx->cc_buffer_saved);
|
||||
|
||||
}
|
||||
|
||||
// Process inbuf bytes in buffer holding and AVC (H.264) video stream.
|
||||
// The number of processed bytes is returned.
|
||||
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
|
||||
size_t process_avc ( struct lib_cc_decode *ctx, unsigned char *avcbuf, size_t avcbuflen ,struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char *bpos = avcbuf;
|
||||
unsigned char *NALstart;
|
||||
@@ -199,16 +239,9 @@ LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbufl
|
||||
"Broken AVC stream - forbidden_zero_bit not zero ...");
|
||||
}
|
||||
|
||||
nal_ref_idc = *NALstart >> 5;
|
||||
unsigned nal_unit_type = *NALstart & 0x1F;
|
||||
|
||||
dvprint("BEGIN NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions before: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
|
||||
|
||||
ctx->avc_ctx->nal_ref_idc = *NALstart >> 5;
|
||||
dvprint("process_avc: zeropad %d\n", zeropad);
|
||||
do_NAL (ctx, NALstart, NALstop-NALstart, sub);
|
||||
|
||||
dvprint("END NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions after: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
|
||||
}
|
||||
|
||||
return avcbuflen;
|
||||
@@ -273,17 +306,19 @@ unsigned char *remove_03emu(unsigned char *from, unsigned char *to)
|
||||
|
||||
// Process SEI payload in AVC data. This function combines sei_rbsp()
|
||||
// and rbsp_trailing_bits().
|
||||
void sei_rbsp (unsigned char *seibuf, unsigned char *seiend)
|
||||
void sei_rbsp (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend)
|
||||
{
|
||||
unsigned char *tbuf = seibuf;
|
||||
while(tbuf < seiend - 1) // Use -1 because of trailing marker
|
||||
{
|
||||
tbuf = sei_message(tbuf, seiend - 1);
|
||||
tbuf = sei_message(ctx, tbuf, seiend - 1);
|
||||
}
|
||||
if(tbuf == seiend - 1 )
|
||||
{
|
||||
if(*tbuf != 0x80)
|
||||
mprint("Strange rbsp_trailing_bits value: %02X\n",*tbuf);
|
||||
else
|
||||
dvprint("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -293,13 +328,13 @@ void sei_rbsp (unsigned char *seibuf, unsigned char *seiend)
|
||||
mprint ("\n Failed block (at sei_rbsp) was:\n");
|
||||
dump (CCX_DMT_GENERIC_NOTICES,(unsigned char *) seibuf, seiend-seibuf,0,0);
|
||||
|
||||
num_unexpected_sei_length++;
|
||||
ctx->num_unexpected_sei_length++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This combines sei_message() and sei_payload().
|
||||
unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend)
|
||||
unsigned char *sei_message (struct avc_ctx *ctx, unsigned char *seibuf, unsigned char *seiend)
|
||||
{
|
||||
int payloadType = 0;
|
||||
while (*seibuf==0xff)
|
||||
@@ -341,26 +376,26 @@ unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend)
|
||||
dbg_print(CCX_DMT_VERBOSE, "\n");
|
||||
// Ignore all except user_data_registered_itu_t_t35() payload
|
||||
if(!broken && payloadType == 4)
|
||||
user_data_registered_itu_t_t35(paystart, paystart+payloadSize);
|
||||
user_data_registered_itu_t_t35(ctx, paystart, paystart+payloadSize);
|
||||
|
||||
return seibuf;
|
||||
}
|
||||
|
||||
void copy_ccdata_to_buffer (char *source, int new_cc_count)
|
||||
void copy_ccdata_to_buffer (struct avc_ctx *ctx, char *source, int new_cc_count)
|
||||
{
|
||||
ccblocks_in_avc_total++;
|
||||
if (cc_buffer_saved==0)
|
||||
ctx->ccblocks_in_avc_total++;
|
||||
if (ctx->cc_buffer_saved == CCX_FALSE)
|
||||
{
|
||||
mprint ("Warning: Probably loss of CC data, unsaved buffer being rewritten\n");
|
||||
ccblocks_in_avc_lost++;
|
||||
mprint ("Warning: Probably loss of CC data, unsaved buffer being rewritten, trailing end might get lost\n");
|
||||
ctx->ccblocks_in_avc_lost++;
|
||||
}
|
||||
memcpy(cc_data+cc_count*3, source, new_cc_count*3+1);
|
||||
cc_count+=new_cc_count;
|
||||
cc_buffer_saved=0;
|
||||
memcpy(ctx->cc_data + ctx->cc_count*3, source, new_cc_count*3+1);
|
||||
ctx->cc_count += new_cc_count;
|
||||
ctx->cc_buffer_saved = CCX_FALSE;
|
||||
}
|
||||
|
||||
|
||||
void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *userend)
|
||||
void user_data_registered_itu_t_t35 (struct avc_ctx *ctx, unsigned char *userbuf, unsigned char *userend)
|
||||
{
|
||||
unsigned char *tbuf = userbuf;
|
||||
unsigned char *cc_tmpdata;
|
||||
@@ -464,15 +499,15 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
"Syntax problem: Final 0xFF marker missing.");
|
||||
|
||||
// Save the data and process once we know the sequence number
|
||||
if (local_cc_count*3+1 > cc_databufsize)
|
||||
if ( ( (ctx->cc_count + local_cc_count) * 3) + 1 > ctx->cc_databufsize)
|
||||
{
|
||||
cc_data = (unsigned char*)realloc(cc_data, (size_t) cc_count*6+1);
|
||||
if (!cc_data)
|
||||
ctx->cc_data = (unsigned char*)realloc(ctx->cc_data, (size_t) ( (ctx->cc_count + local_cc_count) * 6) + 1);
|
||||
if (!ctx->cc_data)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
cc_databufsize = (long) cc_count*6+1;
|
||||
ctx->cc_databufsize = (long) ( (ctx->cc_count + local_cc_count) * 6) + 1;
|
||||
}
|
||||
// Copy new cc data into cc_data
|
||||
copy_ccdata_to_buffer ((char *) cc_tmpdata, local_cc_count);
|
||||
copy_ccdata_to_buffer (ctx, (char *) cc_tmpdata, local_cc_count);
|
||||
break;
|
||||
case 0x06:
|
||||
dbg_print(CCX_DMT_VERBOSE, "bar_data (unsupported for now)\n");
|
||||
@@ -536,15 +571,15 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
"Syntax problem: Final 0xFF marker missing.");
|
||||
|
||||
// Save the data and process once we know the sequence number
|
||||
if (cc_count*3+1 > cc_databufsize)
|
||||
if ( (((local_cc_count + ctx->cc_count) * 3) + 1) > ctx->cc_databufsize)
|
||||
{
|
||||
cc_data = (unsigned char*)realloc(cc_data, (size_t) cc_count*6+1);
|
||||
if (!cc_data)
|
||||
ctx->cc_data = (unsigned char*)realloc(ctx->cc_data, (size_t) (((local_cc_count + ctx->cc_count) * 6) + 1));
|
||||
if (!ctx->cc_data)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
cc_databufsize = (long) cc_count*6+1;
|
||||
ctx->cc_databufsize = (long) (((local_cc_count + ctx->cc_count) * 6) + 1);
|
||||
}
|
||||
// Copy new cc data into cc_data - replace command below.
|
||||
copy_ccdata_to_buffer ((char *) cc_tmpdata, local_cc_count);
|
||||
copy_ccdata_to_buffer (ctx, (char *) cc_tmpdata, local_cc_count);
|
||||
|
||||
//dump(tbuf,user_data_len-1,0);
|
||||
break;
|
||||
@@ -557,7 +592,7 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
|
||||
|
||||
// Process sequence parameters in AVC data.
|
||||
void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
void seq_parameter_set_rbsp (struct avc_ctx *ctx, unsigned char *seqbuf, unsigned char *seqend)
|
||||
{
|
||||
LLONG tmp, tmp1;
|
||||
struct bitstream q1;
|
||||
@@ -583,8 +618,8 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
dvprint("reserved= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,8);
|
||||
dvprint("level_idc= % 4lld (%#llX)\n",tmp,tmp);
|
||||
seq_parameter_set_id = ue(&q1);
|
||||
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", seq_parameter_set_id,seq_parameter_set_id);
|
||||
ctx->seq_parameter_set_id = ue(&q1);
|
||||
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", ctx->seq_parameter_set_id, ctx->seq_parameter_set_id);
|
||||
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
|
||||
|| profile_idc == 244 || profile_idc == 44 || profile_idc == 83
|
||||
|| profile_idc == 86 || profile_idc == 118 || profile_idc == 128){
|
||||
@@ -650,18 +685,18 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
}
|
||||
}
|
||||
}
|
||||
log2_max_frame_num = (int)ue(&q1);
|
||||
dvprint("log2_max_frame_num4_minus4= % 4d (%#X)\n", log2_max_frame_num,log2_max_frame_num);
|
||||
log2_max_frame_num += 4; // 4 is added due to the formula.
|
||||
pic_order_cnt_type = (int)ue(&q1);
|
||||
dvprint("pic_order_cnt_type= % 4d (%#X)\n", pic_order_cnt_type,pic_order_cnt_type);
|
||||
if( pic_order_cnt_type == 0 )
|
||||
ctx->log2_max_frame_num = (int)ue(&q1);
|
||||
dvprint("log2_max_frame_num4_minus4= % 4d (%#X)\n", ctx->log2_max_frame_num, ctx->log2_max_frame_num);
|
||||
ctx->log2_max_frame_num += 4; // 4 is added due to the formula.
|
||||
ctx->pic_order_cnt_type = (int)ue(&q1);
|
||||
dvprint("pic_order_cnt_type= % 4d (%#X)\n", ctx->pic_order_cnt_type, ctx->pic_order_cnt_type);
|
||||
if( ctx->pic_order_cnt_type == 0 )
|
||||
{
|
||||
log2_max_pic_order_cnt_lsb = (int)ue(&q1);
|
||||
dvprint("log2_max_pic_order_cnt_lsb_minus4= % 4d (%#X)\n", log2_max_pic_order_cnt_lsb,log2_max_pic_order_cnt_lsb);
|
||||
log2_max_pic_order_cnt_lsb += 4; // 4 is added due to formula.
|
||||
ctx->log2_max_pic_order_cnt_lsb = (int)ue(&q1);
|
||||
dvprint("log2_max_pic_order_cnt_lsb_minus4= % 4d (%#X)\n", ctx->log2_max_pic_order_cnt_lsb,ctx->log2_max_pic_order_cnt_lsb);
|
||||
ctx->log2_max_pic_order_cnt_lsb += 4; // 4 is added due to formula.
|
||||
}
|
||||
else if( pic_order_cnt_type == 1 )
|
||||
else if( ctx->pic_order_cnt_type == 1 )
|
||||
{
|
||||
// CFS: Untested, just copied from specs.
|
||||
tmp= u(&q1,1);
|
||||
@@ -691,9 +726,9 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
dvprint("pic_width_in_mbs_minus1= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
dvprint("pic_height_in_map_units_minus1= % 4lld (%#llX)\n",tmp,tmp);
|
||||
frame_mbs_only_flag = (int)u(&q1,1);
|
||||
dvprint("frame_mbs_only_flag= % 4d (%#X)\n", frame_mbs_only_flag,frame_mbs_only_flag);
|
||||
if ( !frame_mbs_only_flag )
|
||||
ctx->frame_mbs_only_flag = (int)u(&q1,1);
|
||||
dvprint("frame_mbs_only_flag= % 4d (%#X)\n", ctx->frame_mbs_only_flag, ctx->frame_mbs_only_flag);
|
||||
if ( !ctx->frame_mbs_only_flag )
|
||||
{
|
||||
tmp=u(&q1,1);
|
||||
dvprint("mb_adaptive_fr_fi_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
@@ -785,8 +820,11 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
if (fixed_frame_rate_flag){
|
||||
double clock_tick = (double) num_units_in_tick / time_scale;
|
||||
dvprint("clock_tick= %f\n", clock_tick);
|
||||
current_fps = (double)time_scale / (2 * num_units_in_tick); // Based on formula D-2, p. 359 of the ISO/IEC 14496-10:2012(E) spec.
|
||||
mprint("Changed fps using NAL to: %f\n", current_fps);
|
||||
if (current_fps != (double)time_scale / (2 * num_units_in_tick))
|
||||
{
|
||||
current_fps = (double)time_scale / (2 * num_units_in_tick); // Based on formula D-2, p. 359 of the ISO/IEC 14496-10:2012(E) spec.
|
||||
mprint("Changed fps using NAL to: %f\n", current_fps);
|
||||
}
|
||||
}
|
||||
}
|
||||
tmp = u(&q1,1);
|
||||
@@ -796,7 +834,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
dvprint ("nal_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
//printf("Boom nal_hrd\n");
|
||||
// exit(1);
|
||||
num_nal_hrd++;
|
||||
ctx->num_nal_hrd++;
|
||||
return;
|
||||
}
|
||||
tmp1 = u(&q1,1);
|
||||
@@ -805,7 +843,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
{
|
||||
// TODO.
|
||||
mprint ("vcl_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
num_vcl_hrd++;
|
||||
ctx->num_vcl_hrd++;
|
||||
// exit(1);
|
||||
}
|
||||
if ( tmp || tmp1 )
|
||||
@@ -827,57 +865,53 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
}
|
||||
|
||||
|
||||
// Process slice header in AVC data.
|
||||
void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
|
||||
/**
|
||||
Process slice header in AVC data.
|
||||
Slice Header is parsed to get sequence of frames
|
||||
*/
|
||||
void slice_header (struct lib_cc_decode *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
|
||||
{
|
||||
LLONG tmp;
|
||||
struct bitstream q1;
|
||||
int maxframe_num;
|
||||
LLONG slice_type, bottom_field_flag=0, pic_order_cnt_lsb=-1;
|
||||
int curridx;
|
||||
int IdrPicFlag;
|
||||
LLONG field_pic_flag = 0; // Moved here because it's needed for ctx->avc_ctx->pic_order_cnt_type==2
|
||||
|
||||
if (init_bitstream(&q1, heabuf, heaend))
|
||||
{
|
||||
mprint ("Skipping slice header due to failure in init_bitstream.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LLONG slice_type, bottom_field_flag=0, pic_order_cnt_lsb=-1;
|
||||
static LLONG frame_num=-1, lastframe_num = -1;
|
||||
static int currref=0, maxidx=-1, lastmaxidx=-1;
|
||||
// Used to find tref zero in PTS mode
|
||||
static int minidx=10000, lastminidx=10000;
|
||||
int curridx;
|
||||
int IdrPicFlag = ((nal_unit_type == 5 )?1:0);
|
||||
IdrPicFlag = ((nal_unit_type == 5 )?1:0);
|
||||
|
||||
// Used to remember the max temporal reference number (poc mode)
|
||||
static int maxtref = 0;
|
||||
static int last_gop_maxtref = 0;
|
||||
|
||||
// Used for PTS ordering of CC blocks
|
||||
static LLONG currefpts = 0;
|
||||
|
||||
dvprint("\nSLICE HEADER\n");
|
||||
tmp = ue(&q1);
|
||||
dvprint("first_mb_in_slice= % 4lld (%#llX)\n",tmp,tmp);
|
||||
slice_type = ue(&q1);
|
||||
dvprint("slice_type= %llX\n", slice_type);
|
||||
dvprint("slice_type= % 4llX\n", slice_type);
|
||||
tmp = ue(&q1);
|
||||
dvprint("pic_parameter_set_id= % 4lld (%#llX)\n",tmp,tmp);
|
||||
|
||||
lastframe_num = frame_num;
|
||||
int maxframe_num = (int) ((1<<log2_max_frame_num) - 1);
|
||||
ctx->avc_ctx->lastframe_num = ctx->avc_ctx->frame_num;
|
||||
maxframe_num = (int) ((1<<ctx->avc_ctx->log2_max_frame_num) - 1);
|
||||
|
||||
// Needs log2_max_frame_num_minus4 + 4 bits
|
||||
frame_num = u(&q1,log2_max_frame_num);
|
||||
dvprint("frame_num= %llX\n", frame_num);
|
||||
ctx->avc_ctx->frame_num = u(&q1,ctx->avc_ctx->log2_max_frame_num);
|
||||
dvprint("frame_num= % 4llX\n", ctx->avc_ctx->frame_num);
|
||||
|
||||
LLONG field_pic_flag = 0; // Moved here because it's needed for pic_order_cnt_type==2
|
||||
if( !frame_mbs_only_flag )
|
||||
if( !ctx->avc_ctx->frame_mbs_only_flag )
|
||||
{
|
||||
field_pic_flag = u(&q1,1);
|
||||
dvprint("field_pic_flag= %llX\n", field_pic_flag);
|
||||
dvprint("field_pic_flag= % 4llX\n", field_pic_flag);
|
||||
if( field_pic_flag )
|
||||
{
|
||||
// bottom_field_flag
|
||||
bottom_field_flag = u(&q1,1);
|
||||
dvprint("bottom_field_flag= %llX\n", bottom_field_flag);
|
||||
dvprint("bottom_field_flag= % 4llX\n", bottom_field_flag);
|
||||
|
||||
// TODO - Do this right.
|
||||
// When bottom_field_flag is set the video is interlaced,
|
||||
@@ -886,22 +920,36 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
|
||||
}
|
||||
}
|
||||
|
||||
dvprint("IdrPicFlag= %d\n", IdrPicFlag );
|
||||
dvprint("IdrPicFlag= % 4d\n", IdrPicFlag );
|
||||
|
||||
if( nal_unit_type == 5 )
|
||||
{
|
||||
tmp=ue(&q1);
|
||||
dvprint("idr_pic_id= % 4lld (%#llX)\n",tmp,tmp);
|
||||
dvprint("idr_pic_id= % 4lld (%#llX)\n",tmp,tmp);
|
||||
//TODO
|
||||
}
|
||||
if( pic_order_cnt_type == 0 )
|
||||
if( ctx->avc_ctx->pic_order_cnt_type == 0 )
|
||||
{
|
||||
pic_order_cnt_lsb=u(&q1,log2_max_pic_order_cnt_lsb);
|
||||
dvprint("pic_order_cnt_lsb= %llX\n", pic_order_cnt_lsb);
|
||||
pic_order_cnt_lsb=u(&q1,ctx->avc_ctx->log2_max_pic_order_cnt_lsb);
|
||||
dvprint("pic_order_cnt_lsb= % 4llX\n", pic_order_cnt_lsb);
|
||||
}
|
||||
if( pic_order_cnt_type == 1 )
|
||||
if( ctx->avc_ctx->pic_order_cnt_type == 1 )
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type == 1 not yet supported.");
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: ctx->avc_ctx->pic_order_cnt_type == 1 not yet supported.");
|
||||
}
|
||||
|
||||
//Ignore slice with same pic order or pts
|
||||
if ( ccx_options.usepicorder )
|
||||
{
|
||||
if ( ctx->avc_ctx->last_pic_order_cnt_lsb == pic_order_cnt_lsb)
|
||||
return;
|
||||
ctx->avc_ctx->last_pic_order_cnt_lsb = pic_order_cnt_lsb;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx->timing->current_pts == ctx->avc_ctx->last_slice_pts)
|
||||
return;
|
||||
ctx->avc_ctx->last_slice_pts = ctx->timing->current_pts;
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
@@ -918,7 +966,7 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
|
||||
LLONG tempPicOrderCnt=0;
|
||||
if (IdrPicFlag == 1)
|
||||
tempPicOrderCnt=0;
|
||||
else if (nal_ref_idc == 0)
|
||||
else if (ctx->avc_ctx->nal_ref_idc == 0)
|
||||
tempPicOrderCnt = 2*(FrameNumOffset + frame_num) -1 ;
|
||||
else
|
||||
tempPicOrderCnt = 2*(FrameNumOffset + frame_num);
|
||||
@@ -936,7 +984,7 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
|
||||
|
||||
//pic_order_cnt_lsb=tempPicOrderCnt;
|
||||
//pic_order_cnt_lsb=u(&q1,tempPicOrderCnt);
|
||||
//fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type != 0 not yet supported.");
|
||||
//fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: ctx->avc_ctx->pic_order_cnt_type != 0 not yet supported.");
|
||||
//TODO
|
||||
// Calculate picture order count (POC) according to 8.2.1
|
||||
}
|
||||
@@ -944,44 +992,49 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
|
||||
// The rest of the data in slice_header() is currently unused.
|
||||
|
||||
// A reference pic (I or P is always the last displayed picture of a POC
|
||||
// sequence. B slices can be reference pics, so ignore nal_ref_idc.
|
||||
// sequence. B slices can be reference pics, so ignore ctx->avc_ctx->nal_ref_idc.
|
||||
int isref = 0;
|
||||
switch (slice_type)
|
||||
{
|
||||
// P-SLICES
|
||||
case 0:
|
||||
case 5:
|
||||
// I-SLICES
|
||||
// I-SLICES
|
||||
case 2:
|
||||
case 7:
|
||||
isref=1;
|
||||
break;
|
||||
}
|
||||
|
||||
int maxrefcnt = (int) ((1<<log2_max_pic_order_cnt_lsb) - 1);
|
||||
int maxrefcnt = (int) ((1<<ctx->avc_ctx->log2_max_pic_order_cnt_lsb) - 1);
|
||||
|
||||
// If we saw a jump set maxidx, lastmaxidx to -1
|
||||
LLONG dif = frame_num - lastframe_num;
|
||||
LLONG dif = ctx->avc_ctx->frame_num - ctx->avc_ctx->lastframe_num;
|
||||
if (dif == -maxframe_num)
|
||||
dif = 0;
|
||||
if ( lastframe_num > -1 && (dif < 0 || dif > 1) )
|
||||
if ( ctx->avc_ctx->lastframe_num > -1 && (dif < 0 || dif > 1) )
|
||||
{
|
||||
num_jump_in_frames++;
|
||||
dvprint("\nJump in frame numbers (%lld/%lld)\n", frame_num, lastframe_num);
|
||||
ctx->avc_ctx->num_jump_in_frames++;
|
||||
dvprint("\nJump in frame numbers (%lld/%lld)\n", ctx->avc_ctx->frame_num, ctx->avc_ctx->lastframe_num);
|
||||
// This will prohibit setting current_tref on potential
|
||||
// jumps.
|
||||
maxidx = -1;
|
||||
lastmaxidx = -1;
|
||||
ctx->avc_ctx->maxidx = -1;
|
||||
ctx->avc_ctx->lastmaxidx = -1;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
Leaving it for record, after testing garbled_dishHD.mpg, and
|
||||
2014 SugarHouse Casino Mummers Parade Fancy Brigades_new.ts might need to come back
|
||||
// Sometimes two P-slices follow each other, see garbled_dishHD.mpg,
|
||||
// in this case we only treat the first as a reference pic
|
||||
if (isref && ctx->frames_since_last_gop <= 3) // Used to be == 1, but the sample file
|
||||
{ // 2014 SugarHouse Casino Mummers Parade Fancy Brigades_new.ts was garbled
|
||||
// Probably doing a proper PTS sort would be a better solution.
|
||||
isref = 0;
|
||||
//isref = 0;
|
||||
dbg_print(CCX_DMT_TIME, "Ignoring this reference pic.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// if slices are buffered - flush
|
||||
if (isref)
|
||||
@@ -991,73 +1044,73 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
|
||||
slice_types[slice_type], maxrefcnt);
|
||||
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (has_ccdata_buffered)
|
||||
if (ctx->has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(ctx, sub);
|
||||
}
|
||||
ctx->last_gop_length = ctx->frames_since_last_gop;
|
||||
ctx->frames_since_last_gop = 0;
|
||||
last_gop_maxtref = maxtref;
|
||||
maxtref = 0;
|
||||
lastmaxidx = maxidx;
|
||||
maxidx = 0;
|
||||
lastminidx = minidx;
|
||||
minidx = 10000;
|
||||
ctx->avc_ctx->last_gop_maxtref = ctx->avc_ctx->maxtref;
|
||||
ctx->avc_ctx->maxtref = 0;
|
||||
ctx->avc_ctx->lastmaxidx = ctx->avc_ctx->maxidx;
|
||||
ctx->avc_ctx->maxidx = 0;
|
||||
ctx->avc_ctx->lastminidx = ctx->avc_ctx->minidx;
|
||||
ctx->avc_ctx->minidx = 10000;
|
||||
|
||||
if ( ccx_options.usepicorder ) {
|
||||
// Use pic_order_cnt_lsb
|
||||
|
||||
// Make sure that curridx never wraps for curidx values that
|
||||
// are smaller than currref
|
||||
currref = (int)pic_order_cnt_lsb;
|
||||
if (currref < maxrefcnt/3)
|
||||
ctx->avc_ctx->currref = (int)pic_order_cnt_lsb;
|
||||
if (ctx->avc_ctx->currref < maxrefcnt/3)
|
||||
{
|
||||
currref += maxrefcnt+1;
|
||||
ctx->avc_ctx->currref += maxrefcnt+1;
|
||||
}
|
||||
|
||||
// If we wrapped arround lastmaxidx might be larger than
|
||||
// the current index - fix this.
|
||||
if (lastmaxidx > currref + maxrefcnt/2) // implies lastmaxidx > 0
|
||||
lastmaxidx -=maxrefcnt+1;
|
||||
if (ctx->avc_ctx->lastmaxidx > ctx->avc_ctx->currref + maxrefcnt/2) // implies lastmaxidx > 0
|
||||
ctx->avc_ctx->lastmaxidx -=maxrefcnt+1;
|
||||
} else {
|
||||
// Use PTS ordering
|
||||
currefpts = current_pts;
|
||||
currref = 0;
|
||||
ctx->avc_ctx->currefpts = ctx->timing->current_pts;
|
||||
ctx->avc_ctx->currref = 0;
|
||||
}
|
||||
|
||||
anchor_hdcc( currref );
|
||||
anchor_hdcc( ctx, ctx->avc_ctx->currref );
|
||||
}
|
||||
|
||||
if ( ccx_options.usepicorder ) {
|
||||
// Use pic_order_cnt_lsb
|
||||
// Wrap (add max index value) curridx if needed.
|
||||
if( currref - pic_order_cnt_lsb > maxrefcnt/2 )
|
||||
if( ctx->avc_ctx->currref - pic_order_cnt_lsb > maxrefcnt/2 )
|
||||
curridx = (int)pic_order_cnt_lsb + maxrefcnt+1;
|
||||
else
|
||||
curridx = (int)pic_order_cnt_lsb;
|
||||
|
||||
// Track maximum index for this GOP
|
||||
if ( curridx > maxidx )
|
||||
maxidx = curridx;
|
||||
if ( curridx > ctx->avc_ctx->maxidx )
|
||||
ctx->avc_ctx->maxidx = curridx;
|
||||
|
||||
// Calculate tref
|
||||
if ( lastmaxidx > 0 ) {
|
||||
current_tref = curridx - lastmaxidx -1;
|
||||
if ( ctx->avc_ctx->lastmaxidx > 0 ) {
|
||||
ctx->timing->current_tref = curridx - ctx->avc_ctx->lastmaxidx -1;
|
||||
// Set maxtref
|
||||
if( current_tref > maxtref ) {
|
||||
maxtref = current_tref;
|
||||
if( ctx->timing->current_tref > ctx->avc_ctx->maxtref ) {
|
||||
ctx->avc_ctx->maxtref = ctx->timing->current_tref;
|
||||
}
|
||||
// Now an ugly workaround where pic_order_cnt_lsb increases in
|
||||
// steps of two. The 1.5 is an approximation, it should be:
|
||||
// last_gop_maxtref+1 == last_gop_length*2
|
||||
if ( last_gop_maxtref > ctx->last_gop_length*1.5 ) {
|
||||
current_tref = current_tref/2;
|
||||
if ( ctx->avc_ctx->last_gop_maxtref > ctx->last_gop_length*1.5 ) {
|
||||
ctx->timing->current_tref = ctx->timing->current_tref/2;
|
||||
}
|
||||
}
|
||||
else
|
||||
current_tref = 0;
|
||||
ctx->timing->current_tref = 0;
|
||||
|
||||
if ( current_tref < 0 ) {
|
||||
if ( ctx->timing->current_tref < 0 ) {
|
||||
mprint("current_tref is negative!?\n");
|
||||
}
|
||||
} else {
|
||||
@@ -1065,69 +1118,64 @@ void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char
|
||||
// frame rate
|
||||
// The 2* accounts for a discrepancy between current and actual FPS
|
||||
// seen in some files (CCSample2.mpg)
|
||||
curridx = (int)roundportable(2*(current_pts - currefpts)/(MPEG_CLOCK_FREQ/current_fps));
|
||||
curridx = (int)roundportable(2*(ctx->timing->current_pts - ctx->avc_ctx->currefpts)/(MPEG_CLOCK_FREQ/current_fps));
|
||||
|
||||
if (abs(curridx) >= MAXBFRAMES) {
|
||||
// Probably a jump in the timeline. Warn and handle gracefully.
|
||||
mprint("\nFound large gap in PTS! Trying to recover ...\n");
|
||||
mprint("\nFound large gap(%d) in PTS! Trying to recover ...\n", curridx);
|
||||
curridx = 0;
|
||||
}
|
||||
|
||||
// Track maximum index for this GOP
|
||||
if ( curridx > maxidx )
|
||||
maxidx = curridx;
|
||||
if ( curridx > ctx->avc_ctx->maxidx )
|
||||
ctx->avc_ctx->maxidx = curridx;
|
||||
|
||||
// Track minimum index for this GOP
|
||||
if ( curridx < minidx )
|
||||
minidx = curridx;
|
||||
if ( curridx < ctx->avc_ctx->minidx )
|
||||
ctx->avc_ctx->minidx = curridx;
|
||||
|
||||
current_tref = 1;
|
||||
if ( curridx == lastminidx ) {
|
||||
ctx->timing->current_tref = 1;
|
||||
if ( curridx == ctx->avc_ctx->lastminidx ) {
|
||||
// This implies that the minimal index (assuming its number is
|
||||
// fairly constant) sets the temporal reference to zero - needed to set sync_pts.
|
||||
current_tref = 0;
|
||||
ctx->timing->current_tref = 0;
|
||||
}
|
||||
if ( lastmaxidx == -1) {
|
||||
if ( ctx->avc_ctx->lastmaxidx == -1) {
|
||||
// Set temporal reference to zero on minimal index and in the first GOP
|
||||
// to avoid setting a wrong fts_offset
|
||||
current_tref = 0;
|
||||
ctx->timing->current_tref = 0;
|
||||
}
|
||||
}
|
||||
|
||||
set_fts(); // Keep frames_since_ref_time==0, use current_tref
|
||||
set_fts(ctx->timing); // Keep frames_since_ref_time==0, use current_tref
|
||||
|
||||
dbg_print(CCX_DMT_TIME, "PTS: %s (%8u)",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_TIME, " picordercnt:%3lld tref:%3d idx:%3d refidx:%3d lmaxidx:%3d maxtref:%3d\n",
|
||||
pic_order_cnt_lsb, current_tref,
|
||||
curridx, currref, lastmaxidx, maxtref);
|
||||
dbg_print(CCX_DMT_TIME, "FTS: %s",
|
||||
print_mstime(get_fts()));
|
||||
pic_order_cnt_lsb, ctx->timing->current_tref,
|
||||
curridx, ctx->avc_ctx->currref, ctx->avc_ctx->lastmaxidx, ctx->avc_ctx->maxtref);
|
||||
dbg_print(CCX_DMT_TIME, " sync_pts:%s (%8u)",
|
||||
print_mstime(sync_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (sync_pts));
|
||||
print_mstime(ctx->timing->sync_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (ctx->timing->sync_pts));
|
||||
dbg_print(CCX_DMT_TIME, " - %s since GOP: %2u",
|
||||
slice_types[slice_type],
|
||||
(unsigned) (ctx->frames_since_last_gop));
|
||||
dbg_print(CCX_DMT_TIME, " b:%lld frame# %lld\n", bottom_field_flag, frame_num);
|
||||
dbg_print(CCX_DMT_TIME, " b:%lld frame# %lld\n", bottom_field_flag, ctx->avc_ctx->frame_num);
|
||||
|
||||
// sync_pts is (was) set when current_tref was zero
|
||||
if ( lastmaxidx > -1 && current_tref == 0 )
|
||||
if ( ctx->avc_ctx->lastmaxidx > -1 && ctx->timing->current_tref == 0 )
|
||||
{
|
||||
if (ccx_options.debug_mask & CCX_DMT_TIME )
|
||||
{
|
||||
dbg_print(CCX_DMT_TIME, "\nNew temporal reference:\n");
|
||||
print_debug_timing();
|
||||
print_debug_timing(ctx->timing);
|
||||
}
|
||||
}
|
||||
|
||||
total_frames_count++;
|
||||
ctx->frames_since_last_gop++;
|
||||
|
||||
store_hdcc(ctx, cc_data, cc_count, curridx, fts_now, sub);
|
||||
cc_buffer_saved=1; // CFS: store_hdcc supposedly saves the CC buffer to a sequence buffer
|
||||
cc_count=0;
|
||||
store_hdcc(ctx, ctx->avc_ctx->cc_data, ctx->avc_ctx->cc_count, curridx, ctx->timing->fts_now, sub);
|
||||
ctx->avc_ctx->cc_buffer_saved = CCX_TRUE; // CFS: store_hdcc supposedly saves the CC buffer to a sequence buffer
|
||||
ctx->avc_ctx->cc_count = 0;
|
||||
}
|
||||
|
||||
// max_dec_frame_buffering .. Max frames in buffer
|
||||
|
||||
55
src/lib_ccx/avc_functions.h
Normal file
55
src/lib_ccx/avc_functions.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef AVC_FUNCTION_H
|
||||
#define AVC_FUNCTION_H
|
||||
|
||||
|
||||
struct avc_ctx
|
||||
{
|
||||
unsigned char cc_count;
|
||||
// buffer to hold cc data
|
||||
unsigned char *cc_data;
|
||||
long cc_databufsize;
|
||||
int cc_buffer_saved; // Was the CC buffer saved after it was last updated?
|
||||
|
||||
int got_seq_para;
|
||||
unsigned nal_ref_idc;
|
||||
LLONG seq_parameter_set_id;
|
||||
int log2_max_frame_num;
|
||||
int pic_order_cnt_type;
|
||||
int log2_max_pic_order_cnt_lsb;
|
||||
int frame_mbs_only_flag;
|
||||
|
||||
// Use and throw stats for debug, remove this uglyness soon
|
||||
long num_nal_unit_type_7;
|
||||
long num_vcl_hrd;
|
||||
long num_nal_hrd;
|
||||
long num_jump_in_frames;
|
||||
long num_unexpected_sei_length;
|
||||
|
||||
int ccblocks_in_avc_total;
|
||||
int ccblocks_in_avc_lost;
|
||||
|
||||
LLONG frame_num;
|
||||
LLONG lastframe_num;
|
||||
int currref;
|
||||
int maxidx;
|
||||
int lastmaxidx;
|
||||
|
||||
// Used to find tref zero in PTS mode
|
||||
int minidx;
|
||||
int lastminidx;
|
||||
|
||||
// Used to remember the max temporal reference number (poc mode)
|
||||
int maxtref;
|
||||
int last_gop_maxtref;
|
||||
|
||||
// Used for PTS ordering of CC blocks
|
||||
LLONG currefpts;
|
||||
LLONG last_pic_order_cnt_lsb;
|
||||
LLONG last_slice_pts;
|
||||
};
|
||||
|
||||
struct avc_ctx *init_avc(void);
|
||||
void dinit_avc(struct avc_ctx **ctx);
|
||||
void do_NAL (struct lib_cc_decode *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub);
|
||||
size_t process_avc(struct lib_cc_decode *ctx, unsigned char *avcbuf, size_t avcbuflen, struct cc_subtitle *sub);
|
||||
#endif
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "ccx_common_common.h"
|
||||
|
||||
int cc608_parity_table[256];
|
||||
|
||||
/* printf() for fd instead of FILE*, since dprintf is not portable */
|
||||
void fdprintf(int fd, const char *fmt, ...)
|
||||
{
|
||||
@@ -64,3 +66,63 @@ void freep(void *arg)
|
||||
*ptr = NULL;
|
||||
|
||||
}
|
||||
|
||||
int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
|
||||
LLONG end_time, char *info, char *mode, enum ccx_encoding_type e_type)
|
||||
{
|
||||
if (sub->nb_data)
|
||||
{
|
||||
for(;sub->next;sub = sub->next);
|
||||
sub->next = malloc(sizeof(struct cc_subtitle));
|
||||
if(!sub->next)
|
||||
return -1;
|
||||
sub->next->prev = sub;
|
||||
sub = sub->next;
|
||||
}
|
||||
|
||||
sub->type = CC_TEXT;
|
||||
sub->enc_type = e_type;
|
||||
sub->data = strdup(str);
|
||||
sub->nb_data = strlen(str);
|
||||
sub->start_time = start_time;
|
||||
sub->end_time = end_time;
|
||||
if(info)
|
||||
strncpy(sub->info, info, 4);
|
||||
if(mode)
|
||||
strncpy(sub->mode, mode, 4);
|
||||
sub->got_output = 1;
|
||||
sub->next = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cc608_parity(unsigned int byte)
|
||||
{
|
||||
int ones = 0;
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
if (byte & (1 << i))
|
||||
ones++;
|
||||
}
|
||||
|
||||
return ones & 1;
|
||||
}
|
||||
|
||||
void cc608_build_parity_table(int *parity_table)
|
||||
{
|
||||
unsigned int byte;
|
||||
int parity_v;
|
||||
for (byte = 0; byte <= 127; byte++)
|
||||
{
|
||||
parity_v = cc608_parity(byte);
|
||||
/* CC uses odd parity (i.e., # of 1's in byte is odd.) */
|
||||
parity_table[byte] = parity_v;
|
||||
parity_table[byte | 0x80] = !parity_v;
|
||||
}
|
||||
}
|
||||
|
||||
void build_parity_table (void)
|
||||
{
|
||||
cc608_build_parity_table(cc608_parity_table);
|
||||
}
|
||||
|
||||
@@ -2,19 +2,49 @@
|
||||
#define _CC_COMMON_COMMON
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_structs.h"
|
||||
|
||||
// Define possible exit codes that will be passed on to the fatal function
|
||||
/* Exit codes. Take this seriously as the GUI depends on them.
|
||||
0 means OK as usual,
|
||||
<100 means display whatever was output to stderr as a warning
|
||||
>=100 means display whatever was output to stdout as an error
|
||||
*/
|
||||
#define EXIT_OK 0
|
||||
#define EXIT_NO_INPUT_FILES 2
|
||||
#define EXIT_TOO_MANY_INPUT_FILES 3
|
||||
#define EXIT_INCOMPATIBLE_PARAMETERS 4
|
||||
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
|
||||
#define EXIT_MALFORMED_PARAMETER 7
|
||||
#define EXIT_READ_ERROR 8
|
||||
#define EXIT_NOT_CLASSIFIED 300
|
||||
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
|
||||
#define EXIT_BUFFER_FULL 502
|
||||
#define EXIT_MISSING_ASF_HEADER 1001
|
||||
#define EXIT_MISSING_RCWT_HEADER 1002
|
||||
|
||||
#define CCX_COMMON_EXIT_FILE_CREATION_FAILED 5
|
||||
#define CCX_COMMON_EXIT_UNSUPPORTED 9
|
||||
#define EXIT_NOT_ENOUGH_MEMORY 500
|
||||
#define CCX_COMMON_EXIT_BUG_BUG 1000
|
||||
|
||||
#define CCX_OK 0
|
||||
#define CCX_FALSE 0
|
||||
#define CCX_TRUE 1
|
||||
#define CCX_EAGAIN -100
|
||||
#define CCX_EOF -101
|
||||
#define CCX_EINVAL -102
|
||||
#define CCX_ENOSUPP -103
|
||||
#define CCX_ENOMEM -104
|
||||
|
||||
// Declarations
|
||||
void fdprintf(int fd, const char *fmt, ...);
|
||||
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms);
|
||||
void freep(void *arg);
|
||||
void dbg_print(LLONG mask, const char *fmt, ...);
|
||||
unsigned char *debug_608toASC(unsigned char *ccdata, int channel);
|
||||
int add_cc_sub_text(struct cc_subtitle *sub, char *str, LLONG start_time,
|
||||
LLONG end_time, char *info, char *mode, enum ccx_encoding_type);
|
||||
|
||||
extern int cc608_parity_table[256]; // From myth
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@ extern unsigned char rcwt_header[11];
|
||||
#define TS_PACKET_PAYLOAD_LENGTH 184 // From specs
|
||||
#define SUBLINESIZE 2048 // Max. length of a .srt line - TODO: Get rid of this
|
||||
#define STARTBYTESLENGTH (1024*1024)
|
||||
#define UTF8_MAX_BYTES 6
|
||||
|
||||
#define XMLRPC_CHUNK_SIZE (64*1024) // 64 Kb per chunk, to avoid too many realloc()
|
||||
|
||||
@@ -56,6 +57,7 @@ enum ccx_debug_message_types
|
||||
CCX_DMT_PAT=0x400, // Program Allocation Table dump
|
||||
CCX_DMT_PMT=0x800, // Program Map Table dump
|
||||
CCX_DMT_LEVENSHTEIN=0x1000, // Levenshtein distance calculations
|
||||
CCX_DMT_DUMPDEF=0x2000 // Dump defective TS packets
|
||||
};
|
||||
|
||||
// AVC NAL types
|
||||
@@ -130,6 +132,7 @@ enum ccx_mpeg_descriptor
|
||||
CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR = 0x46,
|
||||
CCX_MPEG_DSC_TELETEXT_DESCRIPTOR = 0x56,
|
||||
CCX_MPEG_DSC_DVB_SUBTITLE = 0x59,
|
||||
CCX_MPEG_DSC_CAPTION_SERVICE = 0x86,
|
||||
CCX_MPEG_DESC_DATA_COMP = 0xfd,
|
||||
};
|
||||
|
||||
@@ -160,6 +163,8 @@ enum ccx_output_format
|
||||
CCX_OF_SMPTETT = 6,
|
||||
CCX_OF_SPUPNG = 7,
|
||||
CCX_OF_DVDRAW = 8, // See -d at http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_TOOLS.HTML#CCExtract
|
||||
CCX_OF_WEBVTT = 9,
|
||||
CCX_OF_SIMPLE_XML = 10,
|
||||
};
|
||||
|
||||
enum ccx_output_date_format
|
||||
@@ -192,7 +197,8 @@ enum ccx_encoding_type
|
||||
{
|
||||
CCX_ENC_UNICODE = 0,
|
||||
CCX_ENC_LATIN_1 = 1,
|
||||
CCX_ENC_UTF_8 = 2
|
||||
CCX_ENC_UTF_8 = 2,
|
||||
CCX_ENC_ASCII = 3
|
||||
};
|
||||
|
||||
enum ccx_bufferdata_type
|
||||
@@ -205,6 +211,7 @@ enum ccx_bufferdata_type
|
||||
CCX_TELETEXT = 5,
|
||||
CCX_PRIVATE_MPEG2_CC = 6,
|
||||
CCX_DVB_SUBTITLE = 7,
|
||||
CCX_ISDB_SUBTITLE = 8,
|
||||
};
|
||||
|
||||
enum ccx_frame_type
|
||||
@@ -228,6 +235,7 @@ enum ccx_code_type
|
||||
CCX_CODEC_TELETEXT,
|
||||
CCX_CODEC_DVB,
|
||||
CCX_CODEC_ISDB_CC,
|
||||
CCX_CODEC_ATSC_CC,
|
||||
CCX_CODEC_NONE,
|
||||
};
|
||||
|
||||
@@ -257,7 +265,7 @@ enum cdp_section_type
|
||||
* should parse f_sel subtitle codec type or not
|
||||
*
|
||||
* @param u_sel pass the codec selected by user to be searched in
|
||||
* all elementry stream, we ignore the not to be selected stream
|
||||
* all elementary stream, we ignore the not to be selected stream
|
||||
* if we find stream this is selected stream. since setting
|
||||
* selected stream and not selected to same codec does not
|
||||
* make ay sense.
|
||||
@@ -276,4 +284,12 @@ enum cdp_section_type
|
||||
|
||||
#define NB_LANGUAGE 5
|
||||
extern const char *language[NB_LANGUAGE];
|
||||
|
||||
#define DEF_VAL_STARTCREDITSNOTBEFORE "0"
|
||||
// To catch the theme after the teaser in TV shows
|
||||
#define DEF_VAL_STARTCREDITSNOTAFTER "5:00"
|
||||
#define DEF_VAL_STARTCREDITSFORATLEAST "2"
|
||||
#define DEF_VAL_STARTCREDITSFORATMOST "5"
|
||||
#define DEF_VAL_ENDCREDITSFORATLEAST "2"
|
||||
#define DEF_VAL_ENDCREDITSFORATMOST "5"
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "utility.h"
|
||||
|
||||
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
|
||||
/* Parameters */
|
||||
void init_options (struct ccx_s_options *options)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
options->buffer_input = 1; // In Windows buffering seems to help
|
||||
options->no_bom = 0;
|
||||
#else
|
||||
options->buffer_input = 0; // In linux, not so much.
|
||||
options->no_bom = 1;
|
||||
#endif
|
||||
options->nofontcolor=0; // 1 = don't put <font color> tags
|
||||
options->notypesetting=0; // 1 = Don't put <i>, <u>, etc typesetting tags
|
||||
|
||||
options->no_bom = 0; // Use BOM by default.
|
||||
|
||||
options->settings_608.direct_rollup = 0;
|
||||
options->settings_608.no_rollup = 0;
|
||||
@@ -23,22 +22,15 @@ void init_options (struct ccx_s_options *options)
|
||||
options->settings_608.screens_to_process = -1;
|
||||
options->settings_608.default_color = COL_TRANSPARENT; // Defaults to transparant/no-color.
|
||||
|
||||
/* Select subtitle codec */
|
||||
options->codec = CCX_CODEC_ANY;
|
||||
options->nocodec = CCX_CODEC_NONE;
|
||||
|
||||
/* Credit stuff */
|
||||
options->start_credits_text=NULL;
|
||||
options->end_credits_text=NULL;
|
||||
options->extract = 1; // Extract 1st field only (primary language)
|
||||
options->cc_channel = 1; // Channel we want to dump in srt mode
|
||||
options->binary_concat=1; // Disabled by -ve or --videoedited
|
||||
options->use_gop_as_pts = 0; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
|
||||
options->fix_padding = 0; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
options->trim_subs=0; // " Remove spaces at sides? "
|
||||
options->gui_mode_reports=0; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
options->no_progress_bar=0; // If 1, suppress the output of the progress to stdout
|
||||
options->sentence_cap =0 ; // FIX CASE? = Fix case?
|
||||
options->enc_cfg.sentence_cap =0 ; // FIX CASE? = Fix case?
|
||||
options->sentence_cap_file=NULL; // Extra words file?
|
||||
options->live_stream=0; // 0 -> A regular file
|
||||
options->messages_target=1; // 1=stdout
|
||||
@@ -57,30 +49,19 @@ void init_options (struct ccx_s_options *options)
|
||||
options->mp4vidtrack=0; // Process the video track even if a CC dedicated track exists.
|
||||
/* General stuff */
|
||||
options->usepicorder = 0; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
|
||||
options->autodash=0; // Add dashes (-) before each speaker automatically?
|
||||
options->xmltv=0; // 1 = full output. 2 = live output. 3 = both
|
||||
options->xmltvliveinterval=10; // interval in seconds between writting xmltv output files in live mode
|
||||
options->xmltvoutputinterval=0; // interval in seconds between writting xmltv full file output
|
||||
options->xmltvonlycurrent=0; // 0 off 1 on
|
||||
options->teletext_mode=CCX_TXT_AUTO_NOT_YET_FOUND; // 0=Disabled, 1 = Not found, 2=Found
|
||||
|
||||
options->transcript_settings = ccx_encoders_default_transcript_settings;
|
||||
options->millis_separator=',';
|
||||
|
||||
options->encoding = CCX_ENC_UTF_8;
|
||||
options->write_format=CCX_OF_SRT; // 0=Raw, 1=srt, 2=SMI
|
||||
options->date_format=ODF_NONE;
|
||||
options->output_filename=NULL;
|
||||
options->out_elementarystream_filename=NULL;
|
||||
options->output_filename = NULL;
|
||||
options->debug_mask=CCX_DMT_GENERIC_NOTICES; // dbg_print will use this mask to print or ignore different types
|
||||
options->debug_mask_on_debug=CCX_DMT_VERBOSE; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
|
||||
options->ts_autoprogram =0; // Try to find a stream with captions automatically (no -pn needed)
|
||||
options->ts_cappid = 0; // PID for stream that holds caption information
|
||||
options->ts_forced_cappid = 0; // If 1, never mess with the selected PID
|
||||
options->ts_forced_program=0; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
options->ts_forced_program_selected=0;
|
||||
options->ts_datastreamtype = -1; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
options->ts_forced_streamtype=CCX_STREAM_TYPE_UNKNOWNSTREAM; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
options->udpaddr = NULL;
|
||||
options->udpport=0; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
@@ -90,20 +71,62 @@ void init_options (struct ccx_s_options *options)
|
||||
options->tcp_desc = NULL;
|
||||
options->srv_addr = NULL;
|
||||
options->srv_port = NULL;
|
||||
options->line_terminator_lf=0; // 0 = CRLF
|
||||
options->noautotimeref=0; // Do NOT set time automatically?
|
||||
options->input_source=CCX_DS_FILE; // Files, stdin or network
|
||||
options->auto_stream = CCX_SM_AUTODETECT;
|
||||
options->m2ts = 0;
|
||||
options->multiprogram = 0;
|
||||
options->out_interval = -1;
|
||||
|
||||
options->subs_delay = 0;
|
||||
|
||||
/* Select subtitle codec */
|
||||
options->demux_cfg.codec = CCX_CODEC_ANY;
|
||||
options->demux_cfg.nocodec = CCX_CODEC_NONE;
|
||||
|
||||
options->demux_cfg.auto_stream = CCX_SM_AUTODETECT;
|
||||
options->demux_cfg.m2ts = 0;
|
||||
options->demux_cfg.out_elementarystream_filename=NULL;
|
||||
options->demux_cfg.ts_autoprogram =0; // Try to find a stream with captions automatically (no -pn needed)
|
||||
options->demux_cfg.ts_cappids[0] = 0; // PID for stream that holds caption information
|
||||
options->demux_cfg.nb_ts_cappid = 0;
|
||||
options->demux_cfg.ts_forced_program = -1; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
options->demux_cfg.ts_forced_program_selected=0;
|
||||
options->demux_cfg.ts_datastreamtype = CCX_STREAM_TYPE_UNKNOWNSTREAM; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
options->demux_cfg.ts_forced_streamtype=CCX_STREAM_TYPE_UNKNOWNSTREAM; // User selected (forced) stream type
|
||||
|
||||
options->enc_cfg.autodash=0; // Add dashes (-) before each speaker automatically?
|
||||
options->enc_cfg.trim_subs=0; // " Remove spaces at sides? "
|
||||
options->enc_cfg.in_format = 1;
|
||||
options->enc_cfg.line_terminator_lf=0; // 0 = CRLF
|
||||
options->enc_cfg.start_credits_text=NULL;
|
||||
options->enc_cfg.end_credits_text=NULL;
|
||||
options->enc_cfg.encoding = CCX_ENC_UTF_8;
|
||||
options->enc_cfg.no_bom = 0; // Use BOM by default.
|
||||
options->enc_cfg.services_charsets = NULL;
|
||||
options->enc_cfg.all_services_charset = NULL;
|
||||
|
||||
options->settings_dtvcc.enabled = 0;
|
||||
options->settings_dtvcc.active_services_count = 0;
|
||||
options->settings_dtvcc.print_file_reports = 1;
|
||||
options->settings_dtvcc.no_rollup = 0;
|
||||
options->settings_dtvcc.report = NULL;
|
||||
memset(options->settings_dtvcc.services_enabled, 0, CCX_DTVCC_MAX_SERVICES);
|
||||
|
||||
// Prepare time structures
|
||||
init_boundary_time (&options->extraction_start);
|
||||
init_boundary_time (&options->extraction_end);
|
||||
init_boundary_time (&options->startcreditsnotbefore);
|
||||
init_boundary_time (&options->startcreditsnotafter);
|
||||
init_boundary_time (&options->startcreditsforatleast);
|
||||
init_boundary_time (&options->startcreditsforatmost);
|
||||
init_boundary_time (&options->endcreditsforatleast);
|
||||
init_boundary_time (&options->endcreditsforatmost);
|
||||
init_boundary_time (&options->enc_cfg.startcreditsnotbefore);
|
||||
init_boundary_time (&options->enc_cfg.startcreditsnotafter);
|
||||
init_boundary_time (&options->enc_cfg.startcreditsforatleast);
|
||||
init_boundary_time (&options->enc_cfg.startcreditsforatmost);
|
||||
init_boundary_time (&options->enc_cfg.endcreditsforatleast);
|
||||
init_boundary_time (&options->enc_cfg.endcreditsforatmost);
|
||||
|
||||
|
||||
// Sensible default values for credits
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &options->enc_cfg.startcreditsnotbefore);
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &options->enc_cfg.startcreditsnotafter);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &options->enc_cfg.startcreditsforatleast);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &options->enc_cfg.startcreditsforatmost);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &options->enc_cfg.endcreditsforatleast);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &options->enc_cfg.endcreditsforatmost);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,72 @@
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_encoders_structs.h"
|
||||
#include "list.h"
|
||||
|
||||
struct demuxer_cfg
|
||||
{
|
||||
int m2ts; // Regular TS or M2TS
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
char *out_elementarystream_filename;
|
||||
|
||||
/* subtitle codec type */
|
||||
enum ccx_code_type codec;
|
||||
enum ccx_code_type nocodec;
|
||||
|
||||
unsigned ts_autoprogram; // Try to find a stream with captions automatically (no -pn needed)
|
||||
unsigned ts_allprogram;
|
||||
unsigned ts_cappids[128]; // PID for stream that holds caption information
|
||||
int nb_ts_cappid;
|
||||
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
|
||||
int ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
unsigned ts_forced_program_selected;
|
||||
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
unsigned ts_forced_streamtype; // User selected (forced) stream type
|
||||
};
|
||||
|
||||
struct encoder_cfg
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int dtvcc_extract; // 1 or 0
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
char *output_filename;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_date_format date_format;
|
||||
char millis_separator;
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
/* Credit stuff */
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
|
||||
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
unsigned int send_to_srv;
|
||||
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
|
||||
char *first_input_file;
|
||||
int multiple_files;
|
||||
int no_font_color;
|
||||
int no_type_setting;
|
||||
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
int program_number;
|
||||
unsigned char in_format;
|
||||
|
||||
//CEA-708
|
||||
int services_enabled[CCX_DTVCC_MAX_SERVICES];
|
||||
char** services_charsets;
|
||||
char* all_services_charset;
|
||||
};
|
||||
struct ccx_s_options // Options from user parameters
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int no_rollup;
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int nofontcolor;
|
||||
@@ -14,26 +77,16 @@ struct ccx_s_options // Options from user parameters
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
int print_file_reports;
|
||||
|
||||
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
|
||||
|
||||
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
|
||||
ccx_decoder_dtvcc_settings settings_dtvcc; //Same for 708 decoder
|
||||
|
||||
/* subtitle codec type */
|
||||
enum ccx_code_type codec;
|
||||
enum ccx_code_type nocodec;
|
||||
/* Credit stuff */
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
char millis_separator;
|
||||
int binary_concat; // Disabled by -ve or --videoedited
|
||||
int use_gop_as_pts; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
int no_progress_bar; // If 1, suppress the output of the progress to stdout
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
char *sentence_cap_file; // Extra words file?
|
||||
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
|
||||
0 -> A regular file
|
||||
@@ -44,7 +97,7 @@ struct ccx_s_options // Options from user parameters
|
||||
int investigate_packets; // Look for captions in all packets when everything else fails
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
int nosync; // Disable syncing
|
||||
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
int wtvconvertfix; // Fix broken Windows 7 conversion
|
||||
int wtvmpeg2;
|
||||
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
|
||||
@@ -52,50 +105,38 @@ struct ccx_s_options // Options from user parameters
|
||||
unsigned mp4vidtrack; // Process the video track even if a CC dedicated track exists.
|
||||
/* General settings */
|
||||
int usepicorder; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
int xmltv; // 1 = full output. 2 = live output. 3 = both
|
||||
int xmltvliveinterval; // interval in seconds between writting xmltv output files in live mode
|
||||
int xmltvoutputinterval; // interval in seconds between writting xmltv full file output
|
||||
int xmltvonlycurrent; // 0 off 1 on
|
||||
unsigned teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
|
||||
|
||||
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
char millis_separator;
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
enum ccx_output_date_format date_format;
|
||||
char *output_filename;
|
||||
char *out_elementarystream_filename;
|
||||
unsigned send_to_srv;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
LLONG debug_mask; // dbg_print will use this mask to print or ignore different types
|
||||
LLONG debug_mask_on_debug; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
|
||||
unsigned ts_autoprogram ; // Try to find a stream with captions automatically (no -pn needed)
|
||||
unsigned ts_cappid ; // PID for stream that holds caption information
|
||||
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
|
||||
unsigned ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
unsigned ts_forced_program_selected;
|
||||
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
unsigned ts_forced_streamtype; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
char *udpaddr;
|
||||
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
unsigned send_to_srv;
|
||||
char *tcpport;
|
||||
char *tcp_password;
|
||||
char *tcp_desc;
|
||||
char *srv_addr;
|
||||
char *srv_port;
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
int noautotimeref; // Do NOT set time automatically?
|
||||
enum ccx_datasource input_source; // Files, stdin or network
|
||||
|
||||
char *output_filename;
|
||||
|
||||
char **inputfile; // List of files to process
|
||||
int num_input_files; // How many?
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
int m2ts; // Regular TS or M2TS
|
||||
struct demuxer_cfg demux_cfg;
|
||||
struct encoder_cfg enc_cfg;
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
// Output structures
|
||||
struct ccx_s_write wbout1;
|
||||
struct ccx_s_write wbout2;
|
||||
int multiprogram;
|
||||
int out_interval;
|
||||
};
|
||||
|
||||
extern struct ccx_s_options ccx_options;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#ifdef _WIN32
|
||||
#define inline _inline
|
||||
#define typeof decltype
|
||||
#include <io.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef _CC_COMMON_STRUCTS
|
||||
#define _CC_COMMON_STRUCTS
|
||||
|
||||
#include "ccx_common_constants.h"
|
||||
|
||||
enum ccx_common_logging_gui {
|
||||
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME, // Called with xds_program_name
|
||||
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR, // Called with current_xds_min, current_xds_hour, current_xds_date, current_xds_month
|
||||
@@ -9,7 +11,7 @@ enum ccx_common_logging_gui {
|
||||
};
|
||||
|
||||
struct ccx_common_logging_t {
|
||||
int debug_mask; // The debug mask that is used to determine if things should be printed or not.
|
||||
LLONG debug_mask; // The debug mask that is used to determine if things should be printed or not.
|
||||
void(*fatal_ftn) (int exit_code, const char *fmt, ...); // Used when an unrecoverable error happens. This should log output/save the error and then exit the program.
|
||||
void(*debug_ftn) (LLONG mask, const char *fmt, ...); // Used to process debug output. Mask can be ignored (custom set by debug_mask).
|
||||
void(*log_ftn)(const char *fmt, ...); // Used to print things. Replacement of standard printf, to allow more control.
|
||||
@@ -21,6 +23,7 @@ enum subtype
|
||||
{
|
||||
CC_BITMAP,
|
||||
CC_608,
|
||||
CC_708,
|
||||
CC_TEXT,
|
||||
CC_RAW,
|
||||
};
|
||||
@@ -28,6 +31,9 @@ enum subtype
|
||||
/**
|
||||
* Raw Subtitle struct used as output of decoder (cc608)
|
||||
* and input for encoder (sami, srt, transcript or smptett etc)
|
||||
*
|
||||
* if subtype CC_BITMAP then data contain nb_data numbers of rectangle
|
||||
* which have to be displayed at same time.
|
||||
*/
|
||||
struct cc_subtitle
|
||||
{
|
||||
@@ -36,18 +42,33 @@ struct cc_subtitle
|
||||
* @warn decoder cant output multiple types of data
|
||||
*/
|
||||
void *data;
|
||||
|
||||
/** number of data */
|
||||
unsigned int nb_data;
|
||||
|
||||
/** type of subtitle */
|
||||
enum subtype type;
|
||||
|
||||
/** Encoding type of Text, must be ignored in case of subtype as bitmap or cc_screen*/
|
||||
enum ccx_encoding_type enc_type;
|
||||
|
||||
/* set only when all the data is to be displayed at same time */
|
||||
LLONG start_time;
|
||||
LLONG end_time;
|
||||
|
||||
/* flags */
|
||||
int flags;
|
||||
|
||||
/* index of language table */
|
||||
int lang_index;
|
||||
|
||||
/** flag to tell that decoder has given output */
|
||||
int got_output;
|
||||
|
||||
char mode[5];
|
||||
char info[4];
|
||||
|
||||
struct cc_subtitle *next;
|
||||
struct cc_subtitle *prev;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -11,32 +11,18 @@
|
||||
// Count 608 (per field) and 708 blocks since last set_fts() call
|
||||
int cb_field1, cb_field2, cb_708;
|
||||
|
||||
int pts_set; //0 = No, 1 = received, 2 = min_pts set
|
||||
int MPEG_CLOCK_FREQ = 90000; // This "constant" is part of the standard
|
||||
|
||||
LLONG min_pts, max_pts, sync_pts;
|
||||
LLONG current_pts = 0;
|
||||
|
||||
int max_dif = 5;
|
||||
unsigned pts_big_change;
|
||||
|
||||
// PTS timing related stuff
|
||||
LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
|
||||
LLONG fts_offset; // Time before first sync_pts
|
||||
LLONG fts_fc_offset; // Time before first GOP
|
||||
LLONG fts_max; // Remember the maximum fts that we saw in current file
|
||||
LLONG fts_global = 0; // Duration of previous files (-ve mode), see c1global
|
||||
|
||||
enum ccx_frame_type current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
int current_tref = 0; // Store temporal reference of current frame
|
||||
double current_fps = (double) 30000.0 / 1001; /* 29.97 */ // TODO: Get from framerates_values[] instead
|
||||
|
||||
int frames_since_ref_time = 0;
|
||||
unsigned total_frames_count;
|
||||
|
||||
// Remember the current field for 608 decoding
|
||||
int current_field = 1; // 1 = field 1, 2 = field 2, 3 = 708
|
||||
|
||||
struct gop_time_code gop_time, first_gop_time, printed_gop;
|
||||
LLONG fts_at_gop_start = 0;
|
||||
int gop_rollover = 0;
|
||||
@@ -51,19 +37,62 @@ void ccx_common_timing_init(LLONG *file_position,int no_sync)
|
||||
ccx_common_timing_settings.no_sync = no_sync;
|
||||
}
|
||||
|
||||
void set_fts(void)
|
||||
void dinit_timing_ctx(struct ccx_common_timing_ctx **arg)
|
||||
{
|
||||
freep(arg);
|
||||
}
|
||||
struct ccx_common_timing_ctx *init_timing_ctx(struct ccx_common_timing_settings_t *cfg)
|
||||
{
|
||||
struct ccx_common_timing_ctx *ctx = malloc(sizeof(struct ccx_common_timing_ctx));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->pts_set = 0;
|
||||
ctx->current_tref = 0;
|
||||
ctx->current_pts = 0;
|
||||
ctx->current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
ctx->min_pts = 0x01FFFFFFFFLL; // 33 bit
|
||||
ctx->max_pts = 0;
|
||||
ctx->sync_pts = 0;
|
||||
ctx->minimum_fts = 0;
|
||||
|
||||
ctx->fts_now = 0; // Time stamp of current file (w/ fts_offset, w/o fts_global)
|
||||
ctx->fts_offset = 0; // Time before first sync_pts
|
||||
ctx->fts_fc_offset = 0; // Time before first GOP
|
||||
ctx->fts_max = 0; // Remember the maximum fts that we saw in current file
|
||||
ctx->fts_global = 0; // Duration of previous files (-ve mode), see c1global
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts)
|
||||
{
|
||||
set_current_pts(ctx, ctx->current_pts + pts);
|
||||
}
|
||||
|
||||
void set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts)
|
||||
{
|
||||
ctx->current_pts = pts;
|
||||
if(ctx->pts_set == 0)
|
||||
ctx->pts_set = 1;
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)", print_mstime(ctx->current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (ctx->current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s \n",print_mstime(ctx->fts_now));
|
||||
}
|
||||
|
||||
int set_fts(struct ccx_common_timing_ctx *ctx)
|
||||
{
|
||||
int pts_jump = 0;
|
||||
|
||||
// ES don't have PTS unless GOP timing is used
|
||||
if (!pts_set && ccx_common_timing_settings.is_elementary_stream)
|
||||
return;
|
||||
if (!ctx->pts_set && ccx_common_timing_settings.is_elementary_stream)
|
||||
return CCX_OK;
|
||||
|
||||
// First check for timeline jump (only when min_pts was set (implies sync_pts)).
|
||||
int dif = 0;
|
||||
if (pts_set == 2)
|
||||
if (ctx->pts_set == 2)
|
||||
{
|
||||
dif=(int) (current_pts-sync_pts)/MPEG_CLOCK_FREQ;
|
||||
dif=(int) (ctx->current_pts - ctx->sync_pts)/MPEG_CLOCK_FREQ;
|
||||
|
||||
if (ccx_common_timing_settings.disable_sync_check){
|
||||
// Disables sync check. Used for several input formats.
|
||||
@@ -74,61 +103,61 @@ void set_fts(void)
|
||||
{
|
||||
// ATSC specs: More than 3501 ms means missing component
|
||||
ccx_common_logging.log_ftn ("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int) dif, *ccx_common_timing_settings.file_position);
|
||||
ccx_common_logging.log_ftn ("Last sync PTS value: %lld\n",sync_pts);
|
||||
ccx_common_logging.log_ftn ("Current PTS value: %lld\n",current_pts);
|
||||
ccx_common_logging.log_ftn ("Last sync PTS value: %lld\n",ctx->sync_pts);
|
||||
ccx_common_logging.log_ftn ("Current PTS value: %lld\n",ctx->current_pts);
|
||||
pts_jump = 1;
|
||||
pts_big_change = 1;
|
||||
|
||||
// Discard the gap if it is not on an I-frame or temporal reference zero.
|
||||
if(current_tref != 0 && current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
|
||||
if(ctx->current_tref != 0 && ctx->current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
|
||||
{
|
||||
fts_now = fts_max;
|
||||
ctx->fts_now = ctx->fts_max;
|
||||
ccx_common_logging.log_ftn ("Change did not occur on first frame - probably a broken GOP\n");
|
||||
return;
|
||||
return CCX_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set min_pts, fts_offset
|
||||
if (pts_set != 0)
|
||||
if (ctx->pts_set != 0)
|
||||
{
|
||||
pts_set = 2;
|
||||
ctx->pts_set = 2;
|
||||
|
||||
// Use this part only the first time min_pts is set. Later treat
|
||||
// it as a reference clock change
|
||||
if (current_pts < min_pts && !pts_jump)
|
||||
if (ctx->current_pts < ctx->min_pts && !pts_jump)
|
||||
{
|
||||
// If this is the first GOP, and seq 0 was not encountered yet
|
||||
// we might reset min_pts/fts_offset again
|
||||
|
||||
min_pts = current_pts;
|
||||
ctx->min_pts = ctx->current_pts;
|
||||
|
||||
// Avoid next async test
|
||||
sync_pts = (LLONG)(current_pts
|
||||
-current_tref*1000.0/current_fps
|
||||
ctx->sync_pts = (LLONG)(ctx->current_pts
|
||||
-ctx->current_tref*1000.0/current_fps
|
||||
*(MPEG_CLOCK_FREQ/1000));
|
||||
|
||||
if(current_tref == 0)
|
||||
if(ctx->current_tref == 0)
|
||||
{ // Earliest time in GOP.
|
||||
fts_offset = 0;
|
||||
ctx->fts_offset = 0;
|
||||
}
|
||||
else if ( total_frames_count-frames_since_ref_time == 0 )
|
||||
{ // If this is the first frame (PES) there cannot be an offset.
|
||||
// This part is also reached for dvr-ms/NTSC (RAW) as
|
||||
// total_frames_count = frames_since_ref_time = 0 when
|
||||
// this is called for the first time.
|
||||
fts_offset = 0;
|
||||
ctx->fts_offset = 0;
|
||||
}
|
||||
else
|
||||
{ // It needs to be "+1" because the current frame is
|
||||
// not yet counted.
|
||||
fts_offset = (LLONG)((total_frames_count
|
||||
ctx->fts_offset = (LLONG)((total_frames_count
|
||||
-frames_since_ref_time+1)
|
||||
*1000.0/current_fps);
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nFirst sync time PTS: %s %+lldms (time before this PTS)\n",
|
||||
print_mstime(min_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
fts_offset );
|
||||
print_mstime(ctx->min_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
ctx->fts_offset );
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n",
|
||||
total_frames_count, frames_since_ref_time);
|
||||
}
|
||||
@@ -139,31 +168,31 @@ void set_fts(void)
|
||||
// The current time in the old time base is calculated using
|
||||
// sync_pts (set at the beginning of the last GOP) plus the
|
||||
// time of the frames since then.
|
||||
fts_offset = fts_offset
|
||||
+ (sync_pts-min_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
ctx->fts_offset = ctx->fts_offset
|
||||
+ (ctx->sync_pts - ctx->min_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ (LLONG) (frames_since_ref_time*1000/current_fps);
|
||||
fts_max = fts_offset;
|
||||
ctx->fts_max = ctx->fts_offset;
|
||||
|
||||
// Start counting again from here
|
||||
pts_set = 1; // Force min to be set again
|
||||
ctx->pts_set = 1; // Force min to be set again
|
||||
|
||||
// Avoid next async test - the gap might have occured on
|
||||
// current_tref != 0.
|
||||
sync_pts = (LLONG) (current_pts
|
||||
-current_tref*1000.0/current_fps
|
||||
ctx->sync_pts = (LLONG) (ctx->current_pts
|
||||
-ctx->current_tref*1000.0/current_fps
|
||||
*(MPEG_CLOCK_FREQ/1000));
|
||||
// Set min_pts = sync_pts as this is used for fts_now
|
||||
min_pts = sync_pts;
|
||||
ctx->min_pts = ctx->sync_pts;
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nNew min PTS time: %s %+lldms (time before this PTS)\n",
|
||||
print_mstime(min_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
fts_offset );
|
||||
print_mstime(ctx->min_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
ctx->fts_offset );
|
||||
}
|
||||
}
|
||||
|
||||
// Set sync_pts, fts_offset
|
||||
if(current_tref == 0)
|
||||
sync_pts = current_pts;
|
||||
if(ctx->current_tref == 0)
|
||||
ctx->sync_pts = ctx->current_pts;
|
||||
|
||||
// Reset counters
|
||||
cb_field1 = 0;
|
||||
@@ -174,53 +203,56 @@ void set_fts(void)
|
||||
// for uninitialized min_pts
|
||||
if (1) // CFS: Remove or think decent condition
|
||||
{
|
||||
if ( pts_set )
|
||||
if ( ctx->pts_set )
|
||||
{
|
||||
// If pts_set is TRUE we have min_pts
|
||||
fts_now = (LLONG)((current_pts-min_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ fts_offset);
|
||||
ctx->fts_now = (LLONG)((ctx->current_pts - ctx->min_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ ctx->fts_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No PTS info at all!!
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG,
|
||||
"No PTS info. Please write bug report.");
|
||||
ccx_common_logging.log_ftn("Set PTS called without any global timestamp set\n");
|
||||
return CCX_EINVAL;
|
||||
}
|
||||
}
|
||||
if ( fts_now > fts_max )
|
||||
if ( ctx->fts_now > ctx->fts_max )
|
||||
{
|
||||
fts_max = fts_now;
|
||||
ctx->fts_max = ctx->fts_now;
|
||||
}
|
||||
return CCX_OK;
|
||||
}
|
||||
|
||||
|
||||
LLONG get_fts(void)
|
||||
LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field)
|
||||
{
|
||||
LLONG fts;
|
||||
|
||||
switch (current_field)
|
||||
{
|
||||
case 1:
|
||||
fts = fts_now + fts_global + cb_field1*1001/30;
|
||||
fts = ctx->fts_now + ctx->fts_global + cb_field1*1001/30;
|
||||
break;
|
||||
case 2:
|
||||
fts = fts_now + fts_global + cb_field2*1001/30;
|
||||
fts = ctx->fts_now + ctx->fts_global + cb_field2*1001/30;
|
||||
break;
|
||||
case 3:
|
||||
fts = fts_now + fts_global + cb_708*1001/30;
|
||||
fts = ctx->fts_now + ctx->fts_global + cb_708*1001/30;
|
||||
break;
|
||||
default:
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "get_fts: unhandled branch");
|
||||
}
|
||||
|
||||
// ccx_common_logging.debug_ftn(CCX_DMT_TIME, "[FTS] "
|
||||
// "fts: %llu, fts_now: %llu, fts_global: %llu, current_field: %llu, cb_708: %llu\n",
|
||||
// fts, fts_now, fts_global, current_field, cb_708);
|
||||
return fts;
|
||||
}
|
||||
|
||||
LLONG get_fts_max(void)
|
||||
LLONG get_fts_max(struct ccx_common_timing_ctx *ctx)
|
||||
{
|
||||
// This returns the maximum FTS that belonged to a frame. Caption block
|
||||
// counters are not applicable.
|
||||
return fts_max + fts_global;
|
||||
return ctx->fts_max + ctx->fts_global;
|
||||
}
|
||||
|
||||
/* Fill a static buffer with a time string (hh:mm:ss:ms) corresponding
|
||||
@@ -243,6 +275,28 @@ char *print_mstime2buf( LLONG mstime , char *buf )
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill buffer with a time string using specified format
|
||||
* @param fmt has to contain 4 format specifiers for h, m, s and ms respectively
|
||||
*/
|
||||
size_t mstime_sprintf(LLONG mstime, char *fmt, char *buf)
|
||||
{
|
||||
unsigned hh, mm, ss, ms;
|
||||
int signoffset = (mstime < 0 ? 1 : 0);
|
||||
|
||||
if (mstime < 0) // Avoid loss of data warning with abs()
|
||||
mstime = -mstime;
|
||||
|
||||
hh = (unsigned) (mstime / 1000 / 60 / 60);
|
||||
mm = (unsigned) (mstime / 1000 / 60 - 60 * hh);
|
||||
ss = (unsigned) (mstime / 1000 - 60 * (mm + 60 * hh));
|
||||
ms = (unsigned) (mstime - 1000 * (ss + 60 * (mm + 60 * hh)));
|
||||
|
||||
buf[0] = '-';
|
||||
return (size_t) sprintf(buf + signoffset, fmt, hh, mm, ss, ms);
|
||||
}
|
||||
|
||||
|
||||
/* Fill a static buffer with a time string (hh:mm:ss:ms) corresponding
|
||||
to the microsecond value in mstime. */
|
||||
char *print_mstime( LLONG mstime )
|
||||
@@ -252,31 +306,31 @@ char *print_mstime( LLONG mstime )
|
||||
}
|
||||
|
||||
/* Helper function for to display debug timing info. */
|
||||
void print_debug_timing( void )
|
||||
void print_debug_timing(struct ccx_common_timing_ctx *ctx)
|
||||
{
|
||||
// Avoid wrong "Calc. difference" and "Asynchronous by" numbers
|
||||
// for uninitialized min_pts
|
||||
LLONG tempmin_pts = (min_pts==0x01FFFFFFFFLL ? sync_pts : min_pts);
|
||||
LLONG tempmin_pts = (ctx->min_pts==0x01FFFFFFFFLL ? ctx->sync_pts : ctx->min_pts);
|
||||
|
||||
ccx_common_logging.log_ftn("Sync time stamps: PTS: %s ",
|
||||
print_mstime((sync_pts)/(MPEG_CLOCK_FREQ/1000)) );
|
||||
print_mstime((ctx->sync_pts)/(MPEG_CLOCK_FREQ/1000)) );
|
||||
ccx_common_logging.log_ftn("GOP: %s \n", print_mstime(gop_time.ms));
|
||||
|
||||
// Length first GOP to last GOP
|
||||
LLONG goplenms = (LLONG) (gop_time.ms - first_gop_time.ms);
|
||||
// Length at last sync point
|
||||
LLONG ptslenms = (unsigned)((sync_pts-tempmin_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ fts_offset);
|
||||
LLONG ptslenms = (unsigned)((ctx->sync_pts-tempmin_pts)/(MPEG_CLOCK_FREQ/1000)
|
||||
+ ctx->fts_offset);
|
||||
|
||||
ccx_common_logging.log_ftn("Last FTS: %s",
|
||||
print_mstime(get_fts_max()));
|
||||
print_mstime(get_fts_max(ctx)));
|
||||
ccx_common_logging.log_ftn(" GOP start FTS: %s\n",
|
||||
print_mstime(fts_at_gop_start));
|
||||
|
||||
// Times are based on last GOP and/or sync time
|
||||
ccx_common_logging.log_ftn("Max FTS diff. to PTS: %6lldms GOP: %6lldms\n\n",
|
||||
get_fts_max()+(LLONG)(1000.0/current_fps)-ptslenms,
|
||||
get_fts_max()+(LLONG)(1000.0/current_fps)-goplenms);
|
||||
get_fts_max(ctx)+(LLONG)(1000.0/current_fps)-ptslenms,
|
||||
get_fts_max(ctx)+(LLONG)(1000.0/current_fps)-goplenms);
|
||||
}
|
||||
|
||||
void calculate_ms_gop_time (struct gop_time_code *g)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef __Timing_H__
|
||||
#define __Timing_H__
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
|
||||
#include "ccx_common_constants.h"
|
||||
struct gop_time_code
|
||||
{
|
||||
int drop_frame_flag;
|
||||
@@ -14,7 +15,8 @@ struct gop_time_code
|
||||
LLONG ms;
|
||||
};
|
||||
|
||||
struct ccx_common_timing_settings_t {
|
||||
struct ccx_common_timing_settings_t
|
||||
{
|
||||
int disable_sync_check; // If 1, timeline jumps will be ignored. This is important in several input formats that are assumed to have correct timing, no matter what.
|
||||
int no_sync; // If 1, there will be no sync at all. Mostly useful for debugging.
|
||||
int is_elementary_stream; // Needs to be set, as it's used in set_fts.
|
||||
@@ -29,44 +31,55 @@ struct ccx_boundary_time
|
||||
int set;
|
||||
};
|
||||
|
||||
struct ccx_common_timing_ctx
|
||||
{
|
||||
int pts_set; //0 = No, 1 = received, 2 = min_pts set
|
||||
LLONG current_pts;
|
||||
enum ccx_frame_type current_picture_coding_type;
|
||||
int current_tref; // Store temporal reference of current frame
|
||||
LLONG min_pts;
|
||||
LLONG max_pts;
|
||||
LLONG sync_pts;
|
||||
LLONG minimum_fts; // No screen should start before this FTS
|
||||
LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
|
||||
LLONG fts_offset; // Time before first sync_pts
|
||||
LLONG fts_fc_offset; // Time before first GOP
|
||||
LLONG fts_max; // Remember the maximum fts that we saw in current file
|
||||
LLONG fts_global; // Duration of previous files (-ve mode)
|
||||
};
|
||||
// Count 608 (per field) and 708 blocks since last set_fts() call
|
||||
extern int cb_field1, cb_field2, cb_708;
|
||||
|
||||
extern int pts_set; //0 = No, 1 = received, 2 = min_pts set
|
||||
extern int MPEG_CLOCK_FREQ; // This is part of the standard
|
||||
|
||||
extern LLONG min_pts, max_pts, sync_pts, current_pts;
|
||||
extern int max_dif;
|
||||
extern unsigned pts_big_change;
|
||||
|
||||
extern LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
|
||||
extern LLONG fts_offset; // Time before first sync_pts
|
||||
extern LLONG fts_fc_offset; // Time before first GOP
|
||||
extern LLONG fts_max; // Remember the maximum fts that we saw in current file
|
||||
extern LLONG fts_global; // Duration of previous files (-ve mode)
|
||||
|
||||
extern enum ccx_frame_type current_picture_coding_type;
|
||||
extern int current_tref; // Store temporal reference of current frame
|
||||
extern double current_fps;
|
||||
extern int frames_since_ref_time;
|
||||
extern unsigned total_frames_count;
|
||||
|
||||
extern int current_field;
|
||||
|
||||
extern struct gop_time_code gop_time, first_gop_time, printed_gop;
|
||||
extern LLONG fts_at_gop_start;
|
||||
extern int gop_rollover;
|
||||
|
||||
void ccx_common_timing_init(LLONG *file_position, int no_sync);
|
||||
|
||||
void set_fts(void);
|
||||
LLONG get_fts(void);
|
||||
LLONG get_fts_max(void);
|
||||
void dinit_timing_ctx(struct ccx_common_timing_ctx **arg);
|
||||
struct ccx_common_timing_ctx *init_timing_ctx(struct ccx_common_timing_settings_t *cfg);
|
||||
|
||||
void set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts);
|
||||
void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts);
|
||||
int set_fts(struct ccx_common_timing_ctx *ctx);
|
||||
LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field);
|
||||
LLONG get_fts_max(struct ccx_common_timing_ctx *ctx);
|
||||
char *print_mstime(LLONG mstime);
|
||||
char *print_mstime2buf(LLONG mstime, char *buf);
|
||||
void print_debug_timing(void);
|
||||
size_t mstime_sprintf(LLONG mstime, char *fmt, char *buf);
|
||||
void print_debug_timing(struct ccx_common_timing_ctx *ctx);
|
||||
int gop_accepted(struct gop_time_code* g);
|
||||
void calculate_ms_gop_time(struct gop_time_code *g);
|
||||
|
||||
#define __Timing_H__
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@ static const int rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10};
|
||||
// Relationship between the first PAC byte and the row number
|
||||
int in_xds_mode=0;
|
||||
|
||||
unsigned char str[2048]; // Another generic general purpose buffer
|
||||
//unsigned char str[2048]; // Another generic general purpose buffer
|
||||
|
||||
const unsigned char pac2_attribs[][3] = // Color, font, ident
|
||||
{
|
||||
@@ -48,8 +48,6 @@ const unsigned char pac2_attribs[][3] = // Color, font, ident
|
||||
{ COL_WHITE, FONT_UNDERLINED, 28 } // 0x5f || 0x7f
|
||||
};
|
||||
|
||||
unsigned char *subline; // Temp storage for .srt lines
|
||||
int new_sentence=1; // Capitalize next letter?
|
||||
|
||||
static const char *command_type[] =
|
||||
{
|
||||
@@ -88,7 +86,8 @@ static const char *cc_modes_text[]=
|
||||
"Pop-Up captions"
|
||||
};
|
||||
#endif
|
||||
const char *color_text[][2]=
|
||||
|
||||
const char *color_text[MAX_COLOR][2]=
|
||||
{
|
||||
{"white",""},
|
||||
{"green","<font color=\"#00ff00\">"},
|
||||
@@ -121,10 +120,9 @@ void ccx_decoder_608_dinit_library(void **ctx)
|
||||
freep(ctx);
|
||||
}
|
||||
ccx_decoder_608_context* ccx_decoder_608_init_library(struct ccx_decoder_608_settings *settings, int channel,
|
||||
int field, int trim_subs,
|
||||
enum ccx_encoding_type encoding, int *halt,
|
||||
int cc_to_stdout, LLONG subs_delay,
|
||||
enum ccx_output_format output_format)
|
||||
int field, int *halt,
|
||||
int cc_to_stdout,
|
||||
enum ccx_output_format output_format, struct ccx_common_timing_ctx *timing)
|
||||
{
|
||||
ccx_decoder_608_context *data = NULL;
|
||||
|
||||
@@ -148,19 +146,18 @@ ccx_decoder_608_context* ccx_decoder_608_init_library(struct ccx_decoder_608_set
|
||||
data->bytes_processed_608 = 0;
|
||||
data->my_field = field;
|
||||
data->my_channel = channel;
|
||||
data->out = NULL;
|
||||
data->have_cursor_position = 0;
|
||||
|
||||
data->trim_subs = trim_subs;
|
||||
data->encoding = encoding;
|
||||
data->output_format = output_format;
|
||||
data->cc_to_stdout = cc_to_stdout;
|
||||
data->textprinted = 0;
|
||||
data->ts_start_of_current_line = 0;
|
||||
|
||||
data->halt = halt;
|
||||
data->cc_to_stdout = cc_to_stdout;
|
||||
data->subs_delay = subs_delay;
|
||||
data->output_format = output_format;
|
||||
|
||||
data->settings = settings;
|
||||
data->current_color = data->settings->default_color;
|
||||
data->report = settings->report;
|
||||
data->timing = timing;
|
||||
|
||||
clear_eia608_cc_buffer(data, &data->buffer1);
|
||||
clear_eia608_cc_buffer(data, &data->buffer2);
|
||||
@@ -229,15 +226,15 @@ void write_char(const unsigned char c, ccx_decoder_608_context *context)
|
||||
if (use_buffer->empty)
|
||||
{
|
||||
if (MODE_POPON != context->mode)
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
|
||||
}
|
||||
use_buffer->empty=0;
|
||||
|
||||
if (context->cursor_column<CCX_DECODER_608_SCREEN_WIDTH - 1)
|
||||
context->cursor_column++;
|
||||
if (context->ts_start_of_current_line == -1)
|
||||
context->ts_start_of_current_line = get_fts();
|
||||
context->ts_last_char_received = get_fts();
|
||||
context->ts_start_of_current_line = get_fts(context->timing, context->my_field);
|
||||
context->ts_last_char_received = get_fts(context->timing, context->my_field);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +301,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
context->current_visible_start_ms = context->ts_start_of_current_line;
|
||||
|
||||
start_time = context->current_visible_start_ms;
|
||||
end_time = get_visible_end() + context->subs_delay;
|
||||
end_time = get_visible_end(context->timing, context->my_field);
|
||||
sub->type = CC_608;
|
||||
data->format = SFORMAT_CC_SCREEN;
|
||||
data->start_time = 0;
|
||||
@@ -313,7 +310,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
data->channel = context->channel;
|
||||
data->my_field = context->my_field;
|
||||
|
||||
if (!data->empty)
|
||||
if (!data->empty && context->output_format != CCX_OF_NULL)
|
||||
{
|
||||
sub->data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
|
||||
if (!sub->data)
|
||||
@@ -357,11 +354,10 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
LLONG end_time;
|
||||
int i = 0;
|
||||
int wrote_something=0;
|
||||
int ret = 0;
|
||||
data = get_current_visible_buffer(context);
|
||||
|
||||
start_time = context->ts_start_of_current_line + context->subs_delay;
|
||||
end_time = get_fts() + context->subs_delay;
|
||||
start_time = context->ts_start_of_current_line;
|
||||
end_time = get_fts(context->timing, context->my_field);
|
||||
sub->type = CC_608;
|
||||
data->format = SFORMAT_CC_LINE;
|
||||
data->start_time = 0;
|
||||
@@ -370,9 +366,7 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
data->channel = context->channel;
|
||||
data->my_field = context->my_field;
|
||||
|
||||
//TODO need to put below functionality in encoder context
|
||||
ret = get_decoder_line_basic (subline, context->cursor_row, data,context->trim_subs,context->encoding);
|
||||
if( ret > 0 )
|
||||
if (!data->empty)
|
||||
{
|
||||
sub->data = (struct eia608_screen *) realloc(sub->data,(sub->nb_data +1) * sizeof(*data));
|
||||
if (!sub->data)
|
||||
@@ -599,7 +593,7 @@ int is_current_row_empty(ccx_decoder_608_context *context)
|
||||
}
|
||||
|
||||
/* Process GLOBAL CODES */
|
||||
void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
void handle_command(unsigned char c1, const unsigned char c2, ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
{
|
||||
int changes=0;
|
||||
|
||||
@@ -763,7 +757,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
roll_up(context); // The roll must be done anyway of course.
|
||||
context->ts_start_of_current_line = -1; // Unknown.
|
||||
if (changes)
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
|
||||
context->cursor_column = 0;
|
||||
break;
|
||||
case COM_ERASENONDISPLAYEDMEMORY:
|
||||
@@ -791,7 +785,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
context->screenfuls_counter++;
|
||||
}
|
||||
erase_memory(context, true);
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
|
||||
break;
|
||||
case COM_ENDOFCAPTION: // Switch buffers
|
||||
// The currently *visible* buffer is leaving, so now we know its ending
|
||||
@@ -799,7 +793,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
context->visible_buffer = (context->visible_buffer == 1) ? 2 : 1;
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
|
||||
context->cursor_column = 0;
|
||||
context->cursor_row = 0;
|
||||
context->current_color = context->settings->default_color;
|
||||
@@ -828,7 +822,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
|
||||
}
|
||||
|
||||
void handle_end_of_data(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
void flush_608_context(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
{
|
||||
// We issue a EraseDisplayedMemory here so if there's any captions pending
|
||||
// they get written to Subtitle.
|
||||
@@ -977,7 +971,7 @@ void erase_both_memories(ccx_decoder_608_context *context, struct cc_subtitle *s
|
||||
// time. Time to actually write it to file.
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
|
||||
context->cursor_column = 0;
|
||||
context->cursor_row = 0;
|
||||
context->current_color = context->settings->default_color;
|
||||
@@ -1075,16 +1069,29 @@ int disCommand(unsigned char hi, unsigned char lo, ccx_decoder_608_context *cont
|
||||
return wrote_to_screen;
|
||||
}
|
||||
|
||||
/* If wb is NULL, then only XDS will be processed */
|
||||
/* If private data is NULL, then only XDS will be processed */
|
||||
int process608(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub)
|
||||
{
|
||||
struct ccx_decoder_608_report *report = NULL;
|
||||
ccx_decoder_608_context *context = private_data;
|
||||
static int textprinted = 0;
|
||||
struct lib_cc_decode *dec_ctx = private_data;
|
||||
struct ccx_decoder_608_context *context;
|
||||
int i;
|
||||
|
||||
if(dec_ctx->current_field == 1)
|
||||
{
|
||||
context = dec_ctx->context_cc608_field_1;
|
||||
}
|
||||
else if (dec_ctx->current_field == 2 && dec_ctx->extract == 1)
|
||||
{
|
||||
context = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
context = dec_ctx->context_cc608_field_2;
|
||||
}
|
||||
if (context)
|
||||
{
|
||||
report = &context->report;
|
||||
report = context->report;
|
||||
context->bytes_processed_608 += length;
|
||||
}
|
||||
if (!data)
|
||||
@@ -1119,16 +1126,16 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
context->channel = 3;
|
||||
if (!in_xds_mode)
|
||||
{
|
||||
ts_start_of_xds=get_fts();
|
||||
in_xds_mode=1;
|
||||
ts_start_of_xds = get_fts(dec_ctx->timing, dec_ctx->current_field);
|
||||
in_xds_mode = 1;
|
||||
}
|
||||
if(report)
|
||||
report->xds=1;
|
||||
report->xds = 1;
|
||||
}
|
||||
if (hi == 0x0F && in_xds_mode && (context == NULL || context->my_field == 2)) // End of XDS block
|
||||
{
|
||||
in_xds_mode=0;
|
||||
do_end_of_xds (sub, lo);
|
||||
do_end_of_xds (sub, dec_ctx->xds_ctx, lo);
|
||||
if (context)
|
||||
context->channel = context->new_channel; // Switch from channel 3
|
||||
continue;
|
||||
@@ -1137,17 +1144,19 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
// http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
|
||||
// http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
|
||||
{
|
||||
// We were writing characters before, start a new line for
|
||||
// diagnostic output from disCommand()
|
||||
if (textprinted == 1 )
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\n");
|
||||
textprinted = 0;
|
||||
}
|
||||
if (!context || context->my_field == 2)
|
||||
in_xds_mode=0; // Back to normal (CEA 608-8.6.2)
|
||||
if (!context) // Not XDS and we don't have a writebuffer, nothing else would have an effect
|
||||
continue;
|
||||
|
||||
// We were writing characters before, start a new line for
|
||||
// diagnostic output from disCommand()
|
||||
if (context->textprinted == 1 )
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\n");
|
||||
context->textprinted = 0;
|
||||
}
|
||||
|
||||
if (context->last_c1 == hi && context->last_c2 == lo)
|
||||
{
|
||||
// Duplicate dual code, discard. Correct to do it only in
|
||||
@@ -1168,7 +1177,7 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
{
|
||||
if (in_xds_mode && (context == NULL || context->my_field == 2))
|
||||
{
|
||||
process_xds_bytes (hi,lo);
|
||||
process_xds_bytes (dec_ctx->xds_ctx, hi, lo);
|
||||
continue;
|
||||
}
|
||||
if (!context) // No XDS code after this point, and user doesn't want captions.
|
||||
@@ -1183,10 +1192,10 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
if (context->channel != context->my_channel)
|
||||
continue;
|
||||
|
||||
if( textprinted == 0 )
|
||||
if( context->textprinted == 0 )
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "\n");
|
||||
textprinted = 1;
|
||||
context->textprinted = 1;
|
||||
}
|
||||
|
||||
handle_single(hi, context);
|
||||
@@ -1196,9 +1205,9 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
context->last_c2 = 0;
|
||||
}
|
||||
|
||||
if (!textprinted && context->channel == context->my_channel)
|
||||
if (!context->textprinted && context->channel == context->my_channel)
|
||||
{ // Current FTS information after the characters are shown
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Current FTS: %s\n", print_mstime(get_fts()));
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Current FTS: %s\n", print_mstime(get_fts(dec_ctx->timing, context->my_field)));
|
||||
//printf(" N:%u", unsigned(fts_now) );
|
||||
//printf(" G:%u", unsigned(fts_global) );
|
||||
//printf(" F:%d %d %d %d\n",
|
||||
@@ -1213,7 +1222,7 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
{
|
||||
// We don't increase screenfuls_counter here.
|
||||
write_cc_buffer(context, sub);
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
context->current_visible_start_ms = get_visible_start(context->timing, context->my_field);
|
||||
}
|
||||
}
|
||||
if (wrote_to_screen && context->cc_to_stdout)
|
||||
|
||||
@@ -13,8 +13,8 @@ extern LLONG ts_start_of_xds;
|
||||
*/
|
||||
struct ccx_decoder_608_report
|
||||
{
|
||||
unsigned xds : 1;
|
||||
unsigned cc_channels[4];
|
||||
uint8_t xds : 1;
|
||||
uint8_t cc_channels[4];
|
||||
};
|
||||
|
||||
typedef struct ccx_decoder_608_settings
|
||||
@@ -24,6 +24,7 @@ typedef struct ccx_decoder_608_settings
|
||||
int no_rollup; // If 1, write one line at a time
|
||||
unsigned char default_color; // Default color to use.
|
||||
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
|
||||
struct ccx_decoder_608_report *report;
|
||||
} ccx_decoder_608_settings;
|
||||
|
||||
typedef struct ccx_decoder_608_context
|
||||
@@ -47,26 +48,21 @@ typedef struct ccx_decoder_608_context
|
||||
int my_field; // Used for sanity checks
|
||||
int my_channel; // Used for sanity checks
|
||||
long bytes_processed_608; // To be written ONLY by process_608
|
||||
struct ccx_s_write *out;
|
||||
int have_cursor_position;
|
||||
|
||||
int trim_subs;
|
||||
enum ccx_encoding_type encoding;
|
||||
|
||||
int *halt; // Can be used to halt the feeding of caption data. Set to 1 if screens_to_progress != -1 && screenfuls_counter >= screens_to_process
|
||||
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
struct ccx_decoder_608_report report;
|
||||
struct ccx_decoder_608_report *report;
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
int textprinted;
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
|
||||
} ccx_decoder_608_context;
|
||||
|
||||
extern unsigned char *enc_buffer;
|
||||
extern unsigned char str[2048];
|
||||
extern unsigned enc_buffer_used;
|
||||
extern unsigned enc_buffer_capacity;
|
||||
|
||||
extern int new_sentence;
|
||||
extern const char *color_text[][2];
|
||||
#define MAX_COLOR 10
|
||||
extern const char *color_text[MAX_COLOR][2];
|
||||
|
||||
typedef enum ccx_decoder_608_color_code
|
||||
{
|
||||
@@ -122,10 +118,9 @@ void ccx_decoder_608_dinit_library(void **ctx);
|
||||
*
|
||||
*/
|
||||
ccx_decoder_608_context* ccx_decoder_608_init_library(struct ccx_decoder_608_settings *settings, int channel,
|
||||
int field, int trim_subs,
|
||||
enum ccx_encoding_type encoding, int *halt,
|
||||
int cc_to_stdout, LLONG subs_delay,
|
||||
enum ccx_output_format output_format);
|
||||
int field, int *halt,
|
||||
int cc_to_stdout,
|
||||
enum ccx_output_format output_format, struct ccx_common_timing_ctx *timing);
|
||||
|
||||
/**
|
||||
* @param data raw cc608 data to be processed
|
||||
@@ -146,7 +141,7 @@ int process608(const unsigned char *data, int length, void *private_data, struct
|
||||
* Issue a EraseDisplayedMemory here so if there's any captions pending
|
||||
* they get written to cc_subtitle
|
||||
*/
|
||||
void handle_end_of_data(ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
void flush_608_context(ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,79 +2,78 @@
|
||||
#define _INCLUDE_708_
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_structs.h"
|
||||
|
||||
#define MAX_708_PACKET_LENGTH 128
|
||||
#define CCX_DECODERS_708_MAX_SERVICES 63
|
||||
#define CCX_DTVCC_MAX_PACKET_LENGTH 128 //According to EIA-708B, part 5
|
||||
#define CCX_DTVCC_MAX_SERVICES 63
|
||||
|
||||
#define I708_MAX_ROWS 15
|
||||
#define I708_MAX_COLUMNS 42
|
||||
#define CCX_DTVCC_MAX_ROWS 15
|
||||
/**
|
||||
* This value should be 32, but there were 16-bit encoded samples (from Korea),
|
||||
* where RowCount calculated another way and equals 46 (23[8bit]*2)
|
||||
*/
|
||||
#define CCX_DTVCC_MAX_COLUMNS (32*2)
|
||||
|
||||
#define I708_SCREENGRID_ROWS 75
|
||||
#define I708_SCREENGRID_COLUMNS 210
|
||||
#define CCX_DTVCC_SCREENGRID_ROWS 75
|
||||
#define CCX_DTVCC_SCREENGRID_COLUMNS 210
|
||||
|
||||
#define I708_MAX_WINDOWS 8
|
||||
#define CCX_DTVCC_MAX_WINDOWS 8
|
||||
|
||||
/*
|
||||
This variable (ccx_decoder_708_report) holds data on the cc channels & xds packets that are encountered during file parse.
|
||||
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
|
||||
for the report functionality.
|
||||
*/
|
||||
struct ccx_decoder_708_report_t
|
||||
#define CCX_DTVCC_FILENAME_TEMPLATE ".p%u.svc%02u"
|
||||
|
||||
#define CCX_DTVCC_NO_LAST_SEQUENCE -1
|
||||
|
||||
enum CCX_DTVCC_COMMANDS_C0_CODES
|
||||
{
|
||||
unsigned services[CCX_DECODERS_708_MAX_SERVICES];
|
||||
};
|
||||
extern struct ccx_decoder_708_report_t ccx_decoder_708_report;
|
||||
|
||||
enum COMMANDS_C0_CODES
|
||||
{
|
||||
NUL=0,
|
||||
ETX=3,
|
||||
BS=8,
|
||||
FF=0xC,
|
||||
CR=0xD,
|
||||
HCR=0xE,
|
||||
EXT1=0x10,
|
||||
P16=0x18
|
||||
CCX_DTVCC_C0_NUL = 0x00,
|
||||
CCX_DTVCC_C0_ETX = 0x03,
|
||||
CCX_DTVCC_C0_BS = 0x08,
|
||||
CCX_DTVCC_C0_FF = 0x0c,
|
||||
CCX_DTVCC_C0_CR = 0x0d,
|
||||
CCX_DTVCC_C0_HCR = 0x0e,
|
||||
CCX_DTVCC_C0_EXT1 = 0x10,
|
||||
CCX_DTVCC_C0_P16 = 0x18
|
||||
};
|
||||
|
||||
enum COMMANDS_C1_CODES
|
||||
enum CCX_DTVCC_COMMANDS_C1_CODES
|
||||
{
|
||||
CW0=0x80,
|
||||
CW1=0x81,
|
||||
CW2=0x82,
|
||||
CW3=0x83,
|
||||
CW4=0x84,
|
||||
CW5=0x85,
|
||||
CW6=0x86,
|
||||
CW7=0x87,
|
||||
CLW=0x88,
|
||||
DSW=0x89,
|
||||
HDW=0x8A,
|
||||
TGW=0x8B,
|
||||
DLW=0x8C,
|
||||
DLY=0x8D,
|
||||
DLC=0x8E,
|
||||
RST=0x8F,
|
||||
SPA=0x90,
|
||||
SPC=0x91,
|
||||
SPL=0x92,
|
||||
RSV93=0x93,
|
||||
RSV94=0x94,
|
||||
RSV95=0x95,
|
||||
RSV96=0x96,
|
||||
SWA=0x97,
|
||||
DF0=0x98,
|
||||
DF1=0x99,
|
||||
DF2=0x9A,
|
||||
DF3=0x9B,
|
||||
DF4=0x9C,
|
||||
DF5=0x9D,
|
||||
DF6=0x9E,
|
||||
DF7=0x9F
|
||||
CCX_DTVCC_C1_CW0 = 0x80,
|
||||
CCX_DTVCC_C1_CW1 = 0x81,
|
||||
CCX_DTVCC_C1_CW2 = 0x82,
|
||||
CCX_DTVCC_C1_CW3 = 0x83,
|
||||
CCX_DTVCC_C1_CW4 = 0x84,
|
||||
CCX_DTVCC_C1_CW5 = 0x85,
|
||||
CCX_DTVCC_C1_CW6 = 0x86,
|
||||
CCX_DTVCC_C1_CW7 = 0x87,
|
||||
CCX_DTVCC_C1_CLW = 0x88,
|
||||
CCX_DTVCC_C1_DSW = 0x89,
|
||||
CCX_DTVCC_C1_HDW = 0x8A,
|
||||
CCX_DTVCC_C1_TGW = 0x8B,
|
||||
CCX_DTVCC_C1_DLW = 0x8C,
|
||||
CCX_DTVCC_C1_DLY = 0x8D,
|
||||
CCX_DTVCC_C1_DLC = 0x8E,
|
||||
CCX_DTVCC_C1_RST = 0x8F,
|
||||
CCX_DTVCC_C1_SPA = 0x90,
|
||||
CCX_DTVCC_C1_SPC = 0x91,
|
||||
CCX_DTVCC_C1_SPL = 0x92,
|
||||
CCX_DTVCC_C1_RSV93 = 0x93,
|
||||
CCX_DTVCC_C1_RSV94 = 0x94,
|
||||
CCX_DTVCC_C1_RSV95 = 0x95,
|
||||
CCX_DTVCC_C1_RSV96 = 0x96,
|
||||
CCX_DTVCC_C1_SWA = 0x97,
|
||||
CCX_DTVCC_C1_DF0 = 0x98,
|
||||
CCX_DTVCC_C1_DF1 = 0x99,
|
||||
CCX_DTVCC_C1_DF2 = 0x9A,
|
||||
CCX_DTVCC_C1_DF3 = 0x9B,
|
||||
CCX_DTVCC_C1_DF4 = 0x9C,
|
||||
CCX_DTVCC_C1_DF5 = 0x9D,
|
||||
CCX_DTVCC_C1_DF6 = 0x9E,
|
||||
CCX_DTVCC_C1_DF7 = 0x9F
|
||||
};
|
||||
|
||||
struct S_COMMANDS_C1
|
||||
struct CCX_DTVCC_S_COMMANDS_C1
|
||||
{
|
||||
int code;
|
||||
const char *name;
|
||||
@@ -82,143 +81,142 @@ struct S_COMMANDS_C1
|
||||
int length;
|
||||
};
|
||||
|
||||
|
||||
enum eWindowsAttribJustify
|
||||
enum ccx_dtvcc_window_justify
|
||||
{
|
||||
left=0,
|
||||
right=1,
|
||||
center=2,
|
||||
full=3
|
||||
CCX_DTVCC_WINDOW_JUSTIFY_LEFT = 0,
|
||||
CCX_DTVCC_WINDOW_JUSTIFY_RIGHT = 1,
|
||||
CCX_DTVCC_WINDOW_JUSTIFY_CENTER = 2,
|
||||
CCX_DTVCC_WINDOW_JUSTIFY_FULL = 3
|
||||
};
|
||||
|
||||
enum eWindowsAttribPrintDirection
|
||||
enum ccx_dtvcc_window_pd //Print Direction
|
||||
{
|
||||
pd_left_to_right=0,
|
||||
pd_right_to_left=1,
|
||||
pd_top_to_bottom=2,
|
||||
pd_bottom_to_top=3
|
||||
CCX_DTVCC_WINDOW_PD_LEFT_RIGHT = 0, //left -> right
|
||||
CCX_DTVCC_WINDOW_PD_RIGHT_LEFT = 1,
|
||||
CCX_DTVCC_WINDOW_PD_TOP_BOTTOM = 2,
|
||||
CCX_DTVCC_WINDOW_PD_BOTTOM_TOP = 3
|
||||
};
|
||||
|
||||
enum eWindowsAttribScrollDirection
|
||||
enum ccx_dtvcc_window_sd //Scroll Direction
|
||||
{
|
||||
sd_left_to_right=0,
|
||||
sd_right_to_left=1,
|
||||
sd_top_to_bottom=2,
|
||||
sd_bottom_to_top=3
|
||||
CCX_DTVCC_WINDOW_SD_LEFT_RIGHT = 0,
|
||||
CCX_DTVCC_WINDOW_SD_RIGHT_LEFT = 1,
|
||||
CCX_DTVCC_WINDOW_SD_TOP_BOTTOM = 2,
|
||||
CCX_DTVCC_WINDOW_SD_BOTTOM_TOP = 3
|
||||
};
|
||||
|
||||
enum eWindowsAttribScrollDisplayEffect
|
||||
enum ccx_dtvcc_window_sde //Scroll Display Effect
|
||||
{
|
||||
snap=0,
|
||||
fade=1,
|
||||
wipe=2
|
||||
CCX_DTVCC_WINDOW_SDE_SNAP = 0,
|
||||
CCX_DTVCC_WINDOW_SDE_FADE = 1,
|
||||
CCX_DTVCC_WINDOW_SDE_WIPE = 2
|
||||
};
|
||||
|
||||
enum eWindowsAttribEffectDirection
|
||||
enum ccx_dtvcc_window_ed //Effect Direction
|
||||
{
|
||||
left_to_right=0,
|
||||
right_to_left=1,
|
||||
top_to_bottom=2,
|
||||
bottom_to_top=3
|
||||
CCX_DTVCC_WINDOW_ED_LEFT_RIGHT = 0,
|
||||
CCX_DTVCC_WINDOW_ED_RIGHT_LEFT = 1,
|
||||
CCX_DTVCC_WINDOW_ED_TOP_BOTTOM = 2,
|
||||
CCX_DTVCC_WINDOW_ED_BOTTOM_TOP = 3
|
||||
};
|
||||
|
||||
enum eWindowsAttribFillOpacity
|
||||
enum ccx_dtvcc_window_fo //Fill Opacity
|
||||
{
|
||||
solid=0,
|
||||
flash=1,
|
||||
traslucent=2,
|
||||
transparent=3
|
||||
CCX_DTVCC_WINDOW_FO_SOLID = 0,
|
||||
CCX_DTVCC_WINDOW_FO_FLASH = 1,
|
||||
CCX_DTVCC_WINDOW_FO_TRANSLUCENT = 2,
|
||||
CCX_DTVCC_WINDOW_FO_TRANSPARENT = 3
|
||||
};
|
||||
|
||||
enum eWindowsAttribBorderType
|
||||
enum ccx_dtvcc_window_border
|
||||
{
|
||||
none=0,
|
||||
raised=1,
|
||||
depressed=2,
|
||||
uniform=3,
|
||||
shadow_left=4,
|
||||
shadow_right=5
|
||||
CCX_DTVCC_WINDOW_BORDER_NONE = 0,
|
||||
CCX_DTVCC_WINDOW_BORDER_RAISED = 1,
|
||||
CCX_DTVCC_WINDOW_BORDER_DEPRESSED = 2,
|
||||
CCX_DTVCC_WINDOW_BORDER_UNIFORM = 3,
|
||||
CCX_DTVCC_WINDOW_BORDER_SHADOW_LEFT = 4,
|
||||
CCX_DTVCC_WINDOW_BORDER_SHADOW_RIGHT = 5
|
||||
};
|
||||
|
||||
enum ePenAttribSize
|
||||
enum ccx_dtvcc_pen_size
|
||||
{
|
||||
pensize_small=0,
|
||||
pensize_standard=1,
|
||||
pensize_large=2
|
||||
CCX_DTVCC_PEN_SIZE_SMALL = 0,
|
||||
CCX_DTVCC_PEN_SIZE_STANDART = 1,
|
||||
CCX_DTVCC_PEN_SIZE_LARGE = 2
|
||||
};
|
||||
|
||||
enum ePenAttribFontStyle
|
||||
enum ccx_dtvcc_pen_font_style
|
||||
{
|
||||
fontstyle_default_or_undefined=0,
|
||||
monospaced_with_serifs=1,
|
||||
proportionally_spaced_with_serifs=2,
|
||||
monospaced_without_serifs=3,
|
||||
proportionally_spaced_without_serifs=4,
|
||||
casual_font_type=5,
|
||||
cursive_font_type=6,
|
||||
small_capitals=7
|
||||
CCX_DTVCC_PEN_FONT_STYLE_DEFAULT_OR_UNDEFINED = 0,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_MONOSPACED_WITH_SERIFS = 1,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_PROPORTIONALLY_SPACED_WITH_SERIFS = 2,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_MONOSPACED_WITHOUT_SERIFS = 3,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_PROPORTIONALLY_SPACED_WITHOUT_SERIFS = 4,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_CASUAL_FONT_TYPE = 5,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_CURSIVE_FONT_TYPE = 6,
|
||||
CCX_DTVCC_PEN_FONT_STYLE_SMALL_CAPITALS = 7
|
||||
};
|
||||
|
||||
enum ePanAttribTextTag
|
||||
enum ccx_dtvcc_pen_text_tag
|
||||
{
|
||||
texttag_dialog=0,
|
||||
texttag_source_or_speaker_id=1,
|
||||
texttag_electronic_voice=2,
|
||||
texttag_foreign_language=3,
|
||||
texttag_voiceover=4,
|
||||
texttag_audible_translation=5,
|
||||
texttag_subtitle_translation=6,
|
||||
texttag_voice_quality_description=7,
|
||||
texttag_song_lyrics=8,
|
||||
texttag_sound_effect_description=9,
|
||||
texttag_musical_score_description=10,
|
||||
texttag_expletitive=11,
|
||||
texttag_undefined_12=12,
|
||||
texttag_undefined_13=13,
|
||||
texttag_undefined_14=14,
|
||||
texttag_not_to_be_displayed=15
|
||||
CCX_DTVCC_PEN_TEXT_TAG_DIALOG = 0,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_SOURCE_OR_SPEAKER_ID = 1,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_ELECTRONIC_VOICE = 2,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_FOREIGN_LANGUAGE = 3,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_VOICEOVER = 4,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_AUDIBLE_TRANSLATION = 5,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_SUBTITLE_TRANSLATION = 6,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_VOICE_QUALITY_DESCRIPTION = 7,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_SONG_LYRICS = 8,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_SOUND_EFFECT_DESCRIPTION = 9,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_MUSICAL_SCORE_DESCRIPTION = 10,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_EXPLETIVE = 11,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_UNDEFINED_12 = 12,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_UNDEFINED_13 = 13,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_UNDEFINED_14 = 14,
|
||||
CCX_DTVCC_PEN_TEXT_TAG_NOT_TO_BE_DISPLAYED = 15
|
||||
};
|
||||
|
||||
enum ePanAttribOffset
|
||||
enum ccx_dtvcc_pen_offset
|
||||
{
|
||||
offset_subscript=0,
|
||||
offset_normal=1,
|
||||
offset_superscript=2
|
||||
CCX_DTVCC_PEN_OFFSET_SUBSCRIPT = 0,
|
||||
CCX_DTVCC_PEN_OFFSET_NORMAL = 1,
|
||||
CCX_DTVCC_PEN_OFFSET_SUPERSCRIPT = 2
|
||||
};
|
||||
|
||||
enum ePanAttribEdgeType
|
||||
enum ccx_dtvcc_pen_edge
|
||||
{
|
||||
edgetype_none=0,
|
||||
edgetype_raised=1,
|
||||
edgetype_depressed=2,
|
||||
edgetype_uniform=3,
|
||||
edgetype_left_drop_shadow=4,
|
||||
edgetype_right_drop_shadow=5
|
||||
CCX_DTVCC_PEN_EDGE_NONE = 0,
|
||||
CCX_DTVCC_PEN_EDGE_RAISED = 1,
|
||||
CCX_DTVCC_PEN_EDGE_DEPRESSED = 2,
|
||||
CCX_DTVCC_PEN_EDGE_UNIFORM = 3,
|
||||
CCX_DTVCC_PEN_EDGE_LEFT_DROP_SHADOW = 4,
|
||||
CCX_DTVCC_PEN_EDGE_RIGHT_DROP_SHADOW = 5
|
||||
};
|
||||
|
||||
enum eAnchorPoints
|
||||
enum ccx_dtvcc_pen_anchor_point
|
||||
{
|
||||
anchorpoint_top_left = 0,
|
||||
anchorpoint_top_center = 1,
|
||||
anchorpoint_top_right =2,
|
||||
anchorpoint_middle_left = 3,
|
||||
anchorpoint_middle_center = 4,
|
||||
anchorpoint_middle_right = 5,
|
||||
anchorpoint_bottom_left = 6,
|
||||
anchorpoint_bottom_center = 7,
|
||||
anchorpoint_bottom_right = 8
|
||||
CCX_DTVCC_ANCHOR_POINT_TOP_LEFT = 0,
|
||||
CCX_DTVCC_ANCHOR_POINT_TOP_CENTER = 1,
|
||||
CCX_DTVCC_ANCHOR_POINT_TOP_RIGHT = 2,
|
||||
CCX_DTVCC_ANCHOR_POINT_MIDDLE_LEFT = 3,
|
||||
CCX_DTVCC_ANCHOR_POINT_MIDDLE_CENTER = 4,
|
||||
CCX_DTVCC_ANCHOR_POINT_MIDDLE_RIGHT = 5,
|
||||
CCX_DTVCC_ANCHOR_POINT_BOTTOM_LEFT = 6,
|
||||
CCX_DTVCC_ANCHOR_POINT_BOTTOM_CENTER = 7,
|
||||
CCX_DTVCC_ANCHOR_POINT_BOTTOM_RIGHT = 8
|
||||
};
|
||||
|
||||
typedef struct e708Pen_color
|
||||
typedef struct ccx_dtvcc_pen_color
|
||||
{
|
||||
int fg_color;
|
||||
int fg_opacity;
|
||||
int bg_color;
|
||||
int bg_opacity;
|
||||
int edge_color;
|
||||
} e708Pen_color;
|
||||
} ccx_dtvcc_pen_color;
|
||||
|
||||
typedef struct e708Pen_attribs
|
||||
typedef struct ccx_dtvcc_pen_attribs
|
||||
{
|
||||
int pen_size;
|
||||
int offset;
|
||||
@@ -227,28 +225,47 @@ typedef struct e708Pen_attribs
|
||||
int edge_type;
|
||||
int underline;
|
||||
int italic;
|
||||
} e708Pen_attribs;
|
||||
} ccx_dtvcc_pen_attribs;
|
||||
|
||||
typedef struct e708Window_attribs
|
||||
typedef struct ccx_dtvcc_window_attribs
|
||||
{
|
||||
int justify;
|
||||
int print_direction;
|
||||
int scroll_direction;
|
||||
int word_wrap;
|
||||
int display_effect;
|
||||
int effect_direction;
|
||||
int effect_speed;
|
||||
int fill_color;
|
||||
int fill_opacity;
|
||||
int border_color;
|
||||
int border_type01;
|
||||
int justify;
|
||||
int scroll_dir;
|
||||
int print_dir;
|
||||
int word_wrap;
|
||||
int border_type;
|
||||
int display_eff;
|
||||
int effect_dir;
|
||||
int effect_speed;
|
||||
} e708Window_attribs;
|
||||
int border_color;
|
||||
} ccx_dtvcc_window_attribs;
|
||||
|
||||
typedef struct e708Window
|
||||
/**
|
||||
* Since 1-byte and 2-byte symbols could appear in captions and
|
||||
* since we have to keep symbols alignment and several windows could appear on a screen at one time,
|
||||
* we use special structure for holding symbols
|
||||
*/
|
||||
typedef struct ccx_dtvcc_symbol
|
||||
{
|
||||
unsigned short sym; //symbol itself, at least 16 bit
|
||||
unsigned char len; //length. could be 1 or 2
|
||||
} ccx_dtvcc_symbol;
|
||||
|
||||
#define CCX_DTVCC_SYM_SET(x, c) {x.len = 1; x.sym = c;}
|
||||
#define CCX_DTVCC_SYM_SET_16(x, c1, c2) {x.len = 2; x.sym = (c1 << 8) | c2;}
|
||||
#define CCX_DTVCC_SYM_IS_16(x) (x.len == 2)
|
||||
#define CCX_DTVCC_SYM(x) ((unsigned char)(x.sym))
|
||||
#define CCX_DTVCC_SYM_16_FIRST(x) ((unsigned char)(x.sym >> 8))
|
||||
#define CCX_DTVCC_SYM_16_SECOND(x) ((unsigned char)(x.sym & 0xff))
|
||||
#define CCX_DTVCC_SYM_IS_EMPTY(x) (x.len == 0)
|
||||
#define CCX_DTVCC_SYM_IS_SET(x) (x.len > 0)
|
||||
|
||||
typedef struct ccx_dtvcc_window
|
||||
{
|
||||
int is_defined;
|
||||
int number; // Handy, in case we only have a pointer to the window
|
||||
int number;
|
||||
int priority;
|
||||
int col_lock;
|
||||
int row_lock;
|
||||
@@ -262,52 +279,94 @@ typedef struct e708Window
|
||||
int pen_style;
|
||||
int win_style;
|
||||
unsigned char commands[6]; // Commands used to create this window
|
||||
e708Window_attribs attribs;
|
||||
e708Pen_attribs pen;
|
||||
e708Pen_color pen_color;
|
||||
ccx_dtvcc_window_attribs attribs;
|
||||
int pen_row;
|
||||
int pen_column;
|
||||
unsigned char *rows[I708_MAX_ROWS+1]; // Max is 15, but we define an extra one for convenience
|
||||
ccx_dtvcc_symbol *rows[CCX_DTVCC_MAX_ROWS];
|
||||
ccx_dtvcc_pen_color pen_colors[CCX_DTVCC_MAX_ROWS];
|
||||
ccx_dtvcc_pen_attribs pen_attribs[CCX_DTVCC_MAX_ROWS];
|
||||
int memory_reserved;
|
||||
int is_empty;
|
||||
} e708Window;
|
||||
LLONG time_ms_show;
|
||||
LLONG time_ms_hide;
|
||||
} ccx_dtvcc_window;
|
||||
|
||||
typedef struct tvscreen
|
||||
typedef struct dtvcc_tv_screen
|
||||
{
|
||||
unsigned char chars[I708_SCREENGRID_ROWS][I708_SCREENGRID_COLUMNS+1];
|
||||
}
|
||||
tvscreen;
|
||||
ccx_dtvcc_symbol chars[CCX_DTVCC_SCREENGRID_ROWS][CCX_DTVCC_SCREENGRID_COLUMNS];
|
||||
ccx_dtvcc_pen_color pen_colors[CCX_DTVCC_SCREENGRID_ROWS];
|
||||
ccx_dtvcc_pen_attribs pen_attribs[CCX_DTVCC_SCREENGRID_ROWS];
|
||||
LLONG time_ms_show;
|
||||
LLONG time_ms_hide;
|
||||
unsigned int cc_count;
|
||||
int service_number;
|
||||
} dtvcc_tv_screen;
|
||||
|
||||
typedef struct cc708_service_decoder
|
||||
/**
|
||||
* Holds data on the CEA 708 services that are encountered during file parse
|
||||
* This can be interesting, so CCExtractor uses it for the report functionality.
|
||||
*/
|
||||
typedef struct ccx_decoder_dtvcc_report
|
||||
{
|
||||
e708Window windows[I708_MAX_WINDOWS];
|
||||
int reset_count;
|
||||
unsigned services[CCX_DTVCC_MAX_SERVICES];
|
||||
} ccx_decoder_dtvcc_report;
|
||||
|
||||
typedef struct ccx_dtvcc_service_decoder
|
||||
{
|
||||
ccx_dtvcc_window windows[CCX_DTVCC_MAX_WINDOWS];
|
||||
int current_window;
|
||||
int inited;
|
||||
LLONG current_visible_start_ms;
|
||||
tvscreen tv1, tv2; // Current and previous "screenfuls", note that we switch between them
|
||||
int is_empty_tv1, is_empty_tv2;
|
||||
int cur_tv; // 1 or 2 rather than 0 or 1, to at least be consistent with the decoder
|
||||
tvscreen *tv; // Pointer to the current TV buffer
|
||||
char *filename; // Where we are going to write our output
|
||||
int fh; // Handle to output file. -1 if not yet open
|
||||
int srt_counter;
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
}
|
||||
cc708_service_decoder;
|
||||
dtvcc_tv_screen *tv;
|
||||
int cc_count;
|
||||
} ccx_dtvcc_service_decoder;
|
||||
|
||||
extern int do_cea708; // Process 708 data?
|
||||
extern int cea708services[]; // [] -> 1 for services to be processed
|
||||
typedef struct ccx_decoder_dtvcc_settings
|
||||
{
|
||||
int enabled;
|
||||
int print_file_reports;
|
||||
int no_rollup;
|
||||
ccx_decoder_dtvcc_report *report;
|
||||
int active_services_count;
|
||||
int services_enabled[CCX_DTVCC_MAX_SERVICES];
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
} ccx_decoder_dtvcc_settings;
|
||||
|
||||
extern int resets_708;
|
||||
/**
|
||||
* TODO
|
||||
* solution requires "sink" or "writer" entity to write captions to output file
|
||||
* decoders have to know nothing about output files
|
||||
*/
|
||||
|
||||
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength);
|
||||
typedef struct ccx_dtvcc_ctx
|
||||
{
|
||||
int is_active;
|
||||
int active_services_count;
|
||||
int services_active[CCX_DTVCC_MAX_SERVICES]; //0 - inactive, 1 - active
|
||||
int report_enabled;
|
||||
|
||||
unsigned char get_internal_from_G0 (unsigned char g0_char);
|
||||
unsigned char get_internal_from_G1 (unsigned char g1_char);
|
||||
unsigned char get_internal_from_G2 (unsigned char g2_char);
|
||||
unsigned char get_internal_from_G3 (unsigned char g3_char);
|
||||
void process_character (cc708_service_decoder *decoder, unsigned char internal_char);
|
||||
ccx_decoder_dtvcc_report *report;
|
||||
|
||||
ccx_dtvcc_service_decoder decoders[CCX_DTVCC_MAX_SERVICES];
|
||||
|
||||
unsigned char current_packet[CCX_DTVCC_MAX_PACKET_LENGTH];
|
||||
int current_packet_length;
|
||||
|
||||
int last_sequence;
|
||||
|
||||
void *encoder; //we can't include header, so keeping it this way
|
||||
int no_rollup;
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
} ccx_dtvcc_ctx;
|
||||
|
||||
|
||||
void ccx_dtvcc_clear_packet(ccx_dtvcc_ctx *ctx);
|
||||
void ccx_dtvcc_windows_reset(ccx_dtvcc_service_decoder *decoder);
|
||||
void ccx_dtvcc_decoder_flush(ccx_dtvcc_ctx *dtvcc, ccx_dtvcc_service_decoder *decoder);
|
||||
|
||||
void ccx_dtvcc_process_current_packet(ccx_dtvcc_ctx *dtvcc);
|
||||
void ccx_dtvcc_process_service_block(ccx_dtvcc_ctx *dtvcc,
|
||||
ccx_dtvcc_service_decoder *decoder,
|
||||
unsigned char *data,
|
||||
int data_length);
|
||||
|
||||
void ccx_decoders_708_init_library(char *basefilename,const char *extension, int report);
|
||||
#endif
|
||||
|
||||
@@ -12,33 +12,33 @@ EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE)
|
||||
A0-FF -> Group G1 as is - non-English characters and symbols
|
||||
*/
|
||||
|
||||
unsigned char get_internal_from_G0 (unsigned char g0_char)
|
||||
unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char)
|
||||
{
|
||||
return g0_char;
|
||||
}
|
||||
|
||||
unsigned char get_internal_from_G1 (unsigned char g1_char)
|
||||
unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char)
|
||||
{
|
||||
return g1_char;
|
||||
}
|
||||
|
||||
// TODO: Probably not right
|
||||
// G2: Extended Control Code Set 1
|
||||
unsigned char get_internal_from_G2 (unsigned char g2_char)
|
||||
unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char)
|
||||
{
|
||||
if (g2_char>=0x20 && g2_char<=0x3F)
|
||||
return g2_char-0x20;
|
||||
if (g2_char>=0x60 && g2_char<=0x7F)
|
||||
return g2_char+0x20;
|
||||
if (g2_char >= 0x20 && g2_char <= 0x3F)
|
||||
return g2_char - (unsigned char)0x20;
|
||||
if (g2_char >= 0x60 && g2_char <= 0x7F)
|
||||
return g2_char + (unsigned char)0x20;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
// TODO: Probably not right
|
||||
// G3: Future Characters and Icon Expansion
|
||||
unsigned char get_internal_from_G3 (unsigned char g3_char)
|
||||
unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char)
|
||||
{
|
||||
if (g3_char==0xa0) // The "CC" (closed captions) sign
|
||||
if (g3_char == 0xa0) // The "CC" (closed captions) sign
|
||||
return 0x06;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
9
src/lib_ccx/ccx_decoders_708_encoding.h
Normal file
9
src/lib_ccx/ccx_decoders_708_encoding.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _CCX_DECODERS_708_ENCODING_H_
|
||||
#define _CCX_DECODERS_708_ENCODING_H_
|
||||
|
||||
unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char);
|
||||
unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char);
|
||||
unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char);
|
||||
unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char);
|
||||
|
||||
#endif /*_CCX_DECODERS_708_ENCODING_H_*/
|
||||
425
src/lib_ccx/ccx_decoders_708_output.c
Normal file
425
src/lib_ccx/ccx_decoders_708_output.c
Normal file
@@ -0,0 +1,425 @@
|
||||
#include "ccx_decoders_708_output.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_common_common.h"
|
||||
|
||||
int _dtvcc_is_row_empty(dtvcc_tv_screen *tv, int row_index)
|
||||
{
|
||||
for (int j = 0; j < CCX_DTVCC_SCREENGRID_COLUMNS; j++)
|
||||
{
|
||||
if (CCX_DTVCC_SYM_IS_SET(tv->chars[row_index][j]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _dtvcc_is_screen_empty(dtvcc_tv_screen *tv)
|
||||
{
|
||||
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
|
||||
{
|
||||
if (!_dtvcc_is_row_empty(tv, i))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _dtvcc_get_write_interval(dtvcc_tv_screen *tv, int row_index, int *first, int *last)
|
||||
{
|
||||
for (*first = 0; *first < CCX_DTVCC_SCREENGRID_COLUMNS; (*first)++)
|
||||
if (CCX_DTVCC_SYM_IS_SET(tv->chars[row_index][*first]))
|
||||
break;
|
||||
for (*last = CCX_DTVCC_SCREENGRID_COLUMNS - 1; *last > 0; (*last)--)
|
||||
if (CCX_DTVCC_SYM_IS_SET(tv->chars[row_index][*last]))
|
||||
break;
|
||||
}
|
||||
|
||||
void _dtvcc_color_to_hex(int color, unsigned *hR, unsigned *hG, unsigned *hB)
|
||||
{
|
||||
*hR = (unsigned) (color >> 4);
|
||||
*hG = (unsigned) ((color >> 2) & 0x3);
|
||||
*hB = (unsigned) (color & 0x3);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] Color: %d [%06x] %u %u %u\n",
|
||||
color, color, *hR, *hG, *hB);
|
||||
}
|
||||
|
||||
void _dtvcc_write_tag_open(dtvcc_tv_screen *tv, struct encoder_ctx *encoder, int row_index)
|
||||
{
|
||||
char *buf = (char *) encoder->buffer;
|
||||
size_t buf_len = 0;
|
||||
|
||||
if (tv->pen_attribs[row_index].italic)
|
||||
buf_len += sprintf(buf + buf_len, "<i>");
|
||||
|
||||
if (tv->pen_attribs[row_index].underline)
|
||||
buf_len += sprintf(buf + buf_len, "<u>");
|
||||
|
||||
if (tv->pen_colors[row_index].fg_color != 0x3f && !encoder->no_font_color) //assuming white is default
|
||||
{
|
||||
unsigned red, green, blue;
|
||||
_dtvcc_color_to_hex(tv->pen_colors[row_index].fg_color, &red, &green, &blue);
|
||||
red = (255 / 3) * red;
|
||||
green = (255 / 3) * green;
|
||||
blue = (255 / 3) * blue;
|
||||
buf_len += sprintf(buf + buf_len, "<font color=\"%02x%02x%02x\">", red, green, blue);
|
||||
}
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, buf_len);
|
||||
}
|
||||
|
||||
void _dtvcc_write_tag_close(dtvcc_tv_screen *tv, struct encoder_ctx *encoder, int row_index)
|
||||
{
|
||||
char *buf = (char *) encoder->buffer;
|
||||
size_t buf_len = 0;
|
||||
|
||||
if (tv->pen_colors[row_index].fg_color != 0x3f && !encoder->no_font_color)
|
||||
buf_len += sprintf(buf + buf_len, "</font>");
|
||||
|
||||
if (tv->pen_attribs[row_index].underline)
|
||||
buf_len += sprintf(buf + buf_len, "</u>");
|
||||
|
||||
if (tv->pen_attribs[row_index].italic)
|
||||
buf_len += sprintf(buf + buf_len, "</i>");
|
||||
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, buf_len);
|
||||
}
|
||||
|
||||
void _dtvcc_write_row(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, int row_index, struct encoder_ctx *encoder)
|
||||
{
|
||||
char *buf = (char *) encoder->buffer;
|
||||
size_t buf_len = 0;
|
||||
memset(buf, 0, INITIAL_ENC_BUFFER_CAPACITY * sizeof(char));
|
||||
int first, last;
|
||||
|
||||
_dtvcc_get_write_interval(tv, row_index, &first, &last);
|
||||
for (int j = first; j <= last; j++)
|
||||
{
|
||||
if (CCX_DTVCC_SYM_IS_16(tv->chars[row_index][j]))
|
||||
{
|
||||
buf[buf_len++] = CCX_DTVCC_SYM_16_FIRST(tv->chars[row_index][j]);
|
||||
buf[buf_len++] = CCX_DTVCC_SYM_16_SECOND(tv->chars[row_index][j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[buf_len++] = CCX_DTVCC_SYM(tv->chars[row_index][j]);
|
||||
}
|
||||
}
|
||||
|
||||
int fd = encoder->dtvcc_writers[tv->service_number - 1].fd;
|
||||
|
||||
if (writer->cd != (iconv_t) -1)
|
||||
{
|
||||
char *encoded_buf = calloc(INITIAL_ENC_BUFFER_CAPACITY, sizeof(char));
|
||||
if (!encoded_buf)
|
||||
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "_dtvcc_write_row");
|
||||
|
||||
char *encoded_buf_start = encoded_buf;
|
||||
|
||||
size_t in_bytes_left = buf_len;
|
||||
size_t out_bytes_left = INITIAL_ENC_BUFFER_CAPACITY * sizeof(char);
|
||||
|
||||
size_t result = iconv(writer->cd, &buf, &in_bytes_left, &encoded_buf, &out_bytes_left);
|
||||
|
||||
if (result == -1)
|
||||
ccx_common_logging.log_ftn("[CEA-708] _dtvcc_write_row: "
|
||||
"conversion failed: %s\n", strerror(errno));
|
||||
|
||||
write(fd, encoded_buf_start, encoded_buf - encoded_buf_start);
|
||||
|
||||
free(encoded_buf_start);
|
||||
}
|
||||
else
|
||||
{
|
||||
write(fd, buf, buf_len);
|
||||
}
|
||||
}
|
||||
|
||||
void ccx_dtvcc_write_srt(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
if (_dtvcc_is_screen_empty(tv))
|
||||
return;
|
||||
|
||||
if (tv->time_ms_show + encoder->subs_delay < 0)
|
||||
return;
|
||||
|
||||
char *buf = (char *) encoder->buffer;
|
||||
memset(buf, 0, INITIAL_ENC_BUFFER_CAPACITY);
|
||||
|
||||
sprintf(buf, "%u%s", tv->cc_count, encoder->encoded_crlf);
|
||||
mstime_sprintf(tv->time_ms_show + encoder->subs_delay,
|
||||
"%02u:%02u:%02u,%03u", buf + strlen(buf));
|
||||
sprintf(buf + strlen(buf), " --> ");
|
||||
mstime_sprintf(tv->time_ms_hide + encoder->subs_delay,
|
||||
"%02u:%02u:%02u,%03u", buf + strlen(buf));
|
||||
sprintf(buf + strlen(buf), (char *) encoder->encoded_crlf);
|
||||
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
|
||||
|
||||
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
|
||||
{
|
||||
if (!_dtvcc_is_row_empty(tv, i))
|
||||
{
|
||||
_dtvcc_write_tag_open(tv, encoder, i);
|
||||
_dtvcc_write_row(writer, tv, i, encoder);
|
||||
_dtvcc_write_tag_close(tv, encoder, i);
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
|
||||
encoder->encoded_crlf, encoder->encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
|
||||
encoder->encoded_crlf, encoder->encoded_crlf_length);
|
||||
}
|
||||
|
||||
void ccx_dtvcc_write_debug(dtvcc_tv_screen *tv)
|
||||
{
|
||||
char tbuf1[SUBLINESIZE],
|
||||
tbuf2[SUBLINESIZE];
|
||||
|
||||
print_mstime2buf(tv->time_ms_show, tbuf1);
|
||||
print_mstime2buf(tv->time_ms_hide, tbuf2);
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "\r%s --> %s\n", tbuf1, tbuf2);
|
||||
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
|
||||
{
|
||||
if (!_dtvcc_is_row_empty(tv, i))
|
||||
{
|
||||
int first, last;
|
||||
_dtvcc_get_write_interval(tv, i, &first, &last);
|
||||
for (int j = first; j <= last; j++)
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "%c", tv->chars[i][j]);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ccx_dtvcc_write_transcript(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
if (_dtvcc_is_screen_empty(tv))
|
||||
return;
|
||||
|
||||
if (tv->time_ms_show + encoder->subs_delay < 0) // Drop screens that because of subs_delay start too early
|
||||
return;
|
||||
|
||||
char *buf = (char *) encoder->buffer;
|
||||
|
||||
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
|
||||
{
|
||||
if (!_dtvcc_is_row_empty(tv, i))
|
||||
{
|
||||
buf[0] = 0;
|
||||
|
||||
if (encoder->transcript_settings->showStartTime)
|
||||
mstime_sprintf(tv->time_ms_show + encoder->subs_delay,
|
||||
"%02u:%02u:%02u,%03u|", buf + strlen(buf));
|
||||
|
||||
if (encoder->transcript_settings->showEndTime)
|
||||
mstime_sprintf(tv->time_ms_hide + encoder->subs_delay,
|
||||
"%02u:%02u:%02u,%03u|", buf + strlen(buf));
|
||||
|
||||
if (encoder->transcript_settings->showCC)
|
||||
sprintf(buf + strlen(buf), "CC1|"); //always CC1 because CEA-708 is field-independent
|
||||
|
||||
if (encoder->transcript_settings->showMode)
|
||||
sprintf(buf + strlen(buf), "POP|"); //TODO caption mode(pop, rollup, etc.)
|
||||
|
||||
if (strlen(buf))
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
|
||||
|
||||
_dtvcc_write_row(writer, tv, i, encoder);
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
|
||||
encoder->encoded_crlf, encoder->encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _dtvcc_write_sami_header(dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
char *buf = (char *) encoder->buffer;
|
||||
memset(buf, 0, INITIAL_ENC_BUFFER_CAPACITY);
|
||||
size_t buf_len = 0;
|
||||
|
||||
buf_len += sprintf(buf + buf_len, "<sami>%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "<head>%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "<style type=\"text/css\">%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "<!--%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len,
|
||||
"p {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;%s",
|
||||
encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len,
|
||||
"text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}%s",
|
||||
encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, ".unknowncc {Name:Unknown; lang:en-US; SAMIType:CC;}%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "-->%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "</style>%s", encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "</head>%s%s", encoder->encoded_crlf, encoder->encoded_crlf);
|
||||
buf_len += sprintf(buf + buf_len, "<body>%s", encoder->encoded_crlf);
|
||||
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, buf_len);
|
||||
}
|
||||
|
||||
void _dtvcc_write_sami_footer(dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
char *buf = (char *) encoder->buffer;
|
||||
sprintf(buf, "</body></sami>");
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
|
||||
encoder->encoded_crlf, encoder->encoded_crlf_length);
|
||||
}
|
||||
|
||||
void ccx_dtvcc_write_sami(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
if (_dtvcc_is_screen_empty(tv))
|
||||
return;
|
||||
|
||||
if (tv->time_ms_show + encoder->subs_delay < 0)
|
||||
return;
|
||||
|
||||
if (tv->cc_count == 1)
|
||||
_dtvcc_write_sami_header(tv, encoder);
|
||||
|
||||
char *buf = (char *) encoder->buffer;
|
||||
|
||||
buf[0] = 0;
|
||||
sprintf(buf, "<sync start=%llu><p class=\"unknowncc\">%s",
|
||||
(unsigned long long) tv->time_ms_show + encoder->subs_delay,
|
||||
encoder->encoded_crlf);
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
|
||||
|
||||
for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++)
|
||||
{
|
||||
if (!_dtvcc_is_row_empty(tv, i))
|
||||
{
|
||||
_dtvcc_write_tag_open(tv, encoder, i);
|
||||
_dtvcc_write_row(writer, tv, i, encoder);
|
||||
_dtvcc_write_tag_close(tv, encoder, i);
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
|
||||
encoder->encoded_br, encoder->encoded_br_length);
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd,
|
||||
encoder->encoded_crlf, encoder->encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(buf, "<sync start=%llu><p class=\"unknowncc\"> </p></sync>%s%s",
|
||||
(unsigned long long) tv->time_ms_hide + encoder->subs_delay,
|
||||
encoder->encoded_crlf, encoder->encoded_crlf);
|
||||
write(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
void _ccx_dtvcc_write(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
switch (encoder->write_format)
|
||||
{
|
||||
case CCX_OF_NULL:
|
||||
break;
|
||||
case CCX_OF_SRT:
|
||||
ccx_dtvcc_write_srt(writer, tv, encoder);
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
ccx_dtvcc_write_transcript(writer, tv, encoder);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
ccx_dtvcc_write_sami(writer, tv, encoder);
|
||||
break;
|
||||
default:
|
||||
ccx_dtvcc_write_debug(tv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ccx_dtvcc_write_done(dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
switch (encoder->write_format)
|
||||
{
|
||||
case CCX_OF_SAMI:
|
||||
_dtvcc_write_sami_footer(tv, encoder);
|
||||
break;
|
||||
default:
|
||||
ccx_common_logging.debug_ftn(
|
||||
CCX_DMT_708, "[CEA-708] ccx_dtvcc_write_done: no handling required\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ccx_dtvcc_writer_init(ccx_dtvcc_writer_ctx *writer,
|
||||
char *base_filename,
|
||||
int program_number,
|
||||
int service_number,
|
||||
enum ccx_output_format write_format,
|
||||
struct encoder_cfg *cfg)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init\n");
|
||||
writer->fd = -1;
|
||||
writer->cd = (iconv_t) -1;
|
||||
if (write_format == CCX_OF_NULL)
|
||||
{
|
||||
writer->filename = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init: "
|
||||
"[%s][%d][%d]\n", base_filename, program_number, service_number);
|
||||
|
||||
char *ext = get_file_extension(write_format);
|
||||
char suffix[32];
|
||||
sprintf(suffix, CCX_DTVCC_FILENAME_TEMPLATE, program_number, service_number);
|
||||
|
||||
writer->filename = create_outfilename(base_filename, suffix, ext);
|
||||
if (!writer->filename)
|
||||
ccx_common_logging.fatal_ftn(
|
||||
EXIT_NOT_ENOUGH_MEMORY, "[CEA-708] _dtvcc_decoder_init_write: not enough memory");
|
||||
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_init: inited [%s]\n", writer->filename);
|
||||
|
||||
char *charset = cfg->all_services_charset ?
|
||||
cfg->all_services_charset :
|
||||
cfg->services_charsets[service_number - 1];
|
||||
|
||||
if (charset)
|
||||
{
|
||||
writer->cd = iconv_open("UTF-8", charset);
|
||||
if (writer->cd == (iconv_t) -1)
|
||||
{
|
||||
ccx_common_logging.fatal_ftn(EXIT_FAILURE, "[CEA-708] dtvcc_init: "
|
||||
"can't create iconv for charset \"%s\": %s\n",
|
||||
charset, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
free(ext);
|
||||
}
|
||||
|
||||
void ccx_dtvcc_writer_cleanup(ccx_dtvcc_writer_ctx *writer)
|
||||
{
|
||||
if (writer->fd >= 0 && writer->fd != STDOUT_FILENO)
|
||||
close(writer->fd);
|
||||
free(writer->filename);
|
||||
if (writer->cd == (iconv_t) -1)
|
||||
{
|
||||
//TODO nothing to do here
|
||||
}
|
||||
else
|
||||
iconv_close(writer->cd);
|
||||
}
|
||||
|
||||
void ccx_dtvcc_writer_output(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] ccx_dtvcc_writer_output: "
|
||||
"writing... [%s][%d]\n", writer->filename, writer->fd);
|
||||
|
||||
if (!writer->filename && writer->fd < 0)
|
||||
return;
|
||||
|
||||
if (writer->filename && writer->fd < 0) //first request to write
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[CEA-708] "
|
||||
"ccx_dtvcc_writer_output: creating %s\n", writer->filename);
|
||||
writer->fd = open(writer->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
if (writer->fd == -1)
|
||||
{
|
||||
ccx_common_logging.fatal_ftn(
|
||||
CCX_COMMON_EXIT_FILE_CREATION_FAILED, "[CEA-708] Failed to open a file\n");
|
||||
}
|
||||
if (!encoder->no_bom)
|
||||
write(writer->fd, UTF8_BOM, sizeof(UTF8_BOM));
|
||||
}
|
||||
|
||||
_ccx_dtvcc_write(writer, tv, encoder);
|
||||
}
|
||||
19
src/lib_ccx/ccx_decoders_708_output.h
Normal file
19
src/lib_ccx/ccx_decoders_708_output.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _CCX_DECODERS_708_OUTPUT_H_
|
||||
#define _CCX_DECODERS_708_OUTPUT_H_
|
||||
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
void ccx_dtvcc_write_done(dtvcc_tv_screen *tv, struct encoder_ctx *encoder);
|
||||
|
||||
void ccx_dtvcc_writer_init(ccx_dtvcc_writer_ctx *writer,
|
||||
char *base_filename,
|
||||
int program_number,
|
||||
int service_number,
|
||||
enum ccx_output_format write_format,
|
||||
struct encoder_cfg *cfg);
|
||||
void ccx_dtvcc_writer_cleanup(ccx_dtvcc_writer_ctx *writer);
|
||||
void ccx_dtvcc_writer_output(ccx_dtvcc_writer_ctx *writer, dtvcc_tv_screen *tv, struct encoder_ctx *encoder);
|
||||
|
||||
#endif /*_CCX_DECODERS_708_OUTPUT_H_*/
|
||||
@@ -8,96 +8,37 @@ made to reuse, not duplicate, as many functions as possible */
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "ccx_decoders_xds.h"
|
||||
#include "ccx_dtvcc.h"
|
||||
|
||||
|
||||
uint64_t utc_refvalue = UINT64_MAX; /* _UI64_MAX means don't use UNIX, 0 = use current system time as reference, +1 use a specific reference */
|
||||
extern int in_xds_mode;
|
||||
|
||||
// Preencoded strings
|
||||
unsigned char encoded_crlf[16];
|
||||
unsigned int encoded_crlf_length;
|
||||
unsigned char encoded_br[16];
|
||||
unsigned int encoded_br_length;
|
||||
|
||||
LLONG minimum_fts = 0; // No screen should start before this FTS
|
||||
|
||||
/* This function returns a FTS that is guaranteed to be at least 1 ms later than the end of the previous screen. It shouldn't be needed
|
||||
obviously but it guarantees there's no timing overlap */
|
||||
LLONG get_visible_start (void)
|
||||
LLONG get_visible_start (struct ccx_common_timing_ctx *ctx, int current_field)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts <= minimum_fts)
|
||||
fts = minimum_fts+1;
|
||||
LLONG fts = get_fts(ctx, current_field);
|
||||
if (fts <= ctx->minimum_fts)
|
||||
fts = ctx->minimum_fts + 1;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible Start time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
|
||||
/* This function returns the current FTS and saves it so it can be used by get_visible_start */
|
||||
LLONG get_visible_end (void)
|
||||
/* This function returns the current FTS and saves it so it can be used by ctxget_visible_start */
|
||||
LLONG get_visible_end (struct ccx_common_timing_ctx *ctx, int current_field)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts>minimum_fts)
|
||||
minimum_fts=fts;
|
||||
LLONG fts = get_fts(ctx, current_field);
|
||||
if (fts > ctx->minimum_fts)
|
||||
ctx->minimum_fts = fts;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible End time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank)
|
||||
{
|
||||
*last_non_blank = -1;
|
||||
*first_non_blank = -1;
|
||||
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
|
||||
{
|
||||
unsigned char c = line[i];
|
||||
if (c != ' ' && c != 0x89)
|
||||
{
|
||||
if (*first_non_blank == -1)
|
||||
*first_non_blank = i;
|
||||
*last_non_blank = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding)
|
||||
{
|
||||
unsigned char *line = data->characters[line_num];
|
||||
int last_non_blank = -1;
|
||||
int first_non_blank = -1;
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
find_limit_characters(line, &first_non_blank, &last_non_blank);
|
||||
if (!trim_subs)
|
||||
first_non_blank = 0;
|
||||
|
||||
if (first_non_blank == -1)
|
||||
{
|
||||
*buffer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytes = 0;
|
||||
for (int i = first_non_blank; i <= last_non_blank; i++)
|
||||
{
|
||||
char c = line[i];
|
||||
switch (encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
bytes = get_char_in_utf_8(buffer, c);
|
||||
break;
|
||||
case CCX_ENC_LATIN_1:
|
||||
get_char_in_latin_1(buffer, c);
|
||||
bytes = 1;
|
||||
break;
|
||||
case CCX_ENC_UNICODE:
|
||||
get_char_in_unicode(buffer, c);
|
||||
bytes = 2;
|
||||
break;
|
||||
}
|
||||
buffer += bytes;
|
||||
}
|
||||
*buffer = 0;
|
||||
return (unsigned)(buffer - orig); // Return length
|
||||
}
|
||||
|
||||
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub)
|
||||
{
|
||||
int ret = -1;
|
||||
@@ -161,13 +102,13 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
return 1;
|
||||
|
||||
// Print raw data with FTS.
|
||||
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(fts_now + fts_global),in_xds_mode,
|
||||
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(ctx->timing->fts_now + ctx->timing->fts_global),in_xds_mode,
|
||||
cc_block[0], cc_block[1]&0x7f,cc_block[2]&0x7f, cc_block[2]);
|
||||
|
||||
/* In theory the writercwtdata() function could return early and not
|
||||
* go through the 608/708 cases below. We do that to get accurate
|
||||
* counts for cb_field1, cb_field2 and cb_708.
|
||||
* Note that printdata() and do_708() must not be called for
|
||||
* Note that printdata() and dtvcc_process_data() must not be called for
|
||||
* the CCX_OF_RCWT case. */
|
||||
|
||||
if (cc_valid || cc_type==3)
|
||||
@@ -179,14 +120,14 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
case 0:
|
||||
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
|
||||
|
||||
current_field=1;
|
||||
ctx->current_field = 1;
|
||||
ctx->saw_caption_block = 1;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts() < ctx->extraction_start.time_in_ms)
|
||||
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts() > ctx->extraction_end.time_in_ms)
|
||||
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
@@ -203,14 +144,14 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
case 1:
|
||||
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
|
||||
|
||||
current_field=2;
|
||||
ctx->current_field = 2;
|
||||
ctx->saw_caption_block = 1;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts() < ctx->extraction_start.time_in_ms)
|
||||
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts() > ctx->extraction_end.time_in_ms)
|
||||
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
@@ -231,13 +172,13 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
|
||||
|
||||
// DTVCC packet start
|
||||
current_field=3;
|
||||
ctx->current_field = 3;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts() < ctx->extraction_start.time_in_ms)
|
||||
get_fts(ctx->timing, ctx->current_field) < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts() > ctx->extraction_end.time_in_ms)
|
||||
get_fts(ctx->timing, ctx->current_field) > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
@@ -249,8 +190,8 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
temp[3]=cc_block[2];
|
||||
if (timeok)
|
||||
{
|
||||
if(ctx->write_format!=CCX_OF_RCWT)
|
||||
do_708 (ctx,(const unsigned char *) temp, 4);
|
||||
if (ctx->write_format != CCX_OF_RCWT)
|
||||
ccx_dtvcc_process_data(ctx, (const unsigned char *) temp, 4);
|
||||
else
|
||||
writercwtdata(ctx, cc_block, sub);
|
||||
}
|
||||
@@ -270,6 +211,18 @@ int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitl
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dinit_cc_decode(struct lib_cc_decode **ctx)
|
||||
{
|
||||
struct lib_cc_decode *lctx = *ctx;
|
||||
ccx_dtvcc_free(&lctx->dtvcc);
|
||||
dinit_avc(&lctx->avc_ctx);
|
||||
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1);
|
||||
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2);
|
||||
dinit_timing_ctx(&lctx->timing);
|
||||
freep(ctx);
|
||||
}
|
||||
|
||||
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting)
|
||||
{
|
||||
struct lib_cc_decode *ctx = NULL;
|
||||
@@ -278,36 +231,60 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
// Prepare 608 context
|
||||
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
|
||||
setting->settings_608,
|
||||
setting->cc_channel,
|
||||
1,
|
||||
setting->trim_subs,
|
||||
setting->encoding,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->subs_delay,
|
||||
setting->output_format
|
||||
);
|
||||
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
|
||||
setting->settings_608,
|
||||
setting->cc_channel,
|
||||
2,
|
||||
setting->trim_subs,
|
||||
setting->encoding,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->subs_delay,
|
||||
setting->output_format
|
||||
);
|
||||
ctx->avc_ctx = init_avc();
|
||||
ctx->codec = setting->codec;
|
||||
ctx->timing = init_timing_ctx(&ccx_common_timing_settings);
|
||||
|
||||
setting->settings_dtvcc->timing = ctx->timing;
|
||||
|
||||
setting->settings_608->no_rollup = setting->no_rollup;
|
||||
setting->settings_dtvcc->no_rollup = setting->no_rollup;
|
||||
ctx->no_rollup = setting->no_rollup;
|
||||
|
||||
ctx->dtvcc = ccx_dtvcc_init(setting->settings_dtvcc);
|
||||
ctx->dtvcc->is_active = setting->settings_dtvcc->enabled;
|
||||
|
||||
if(setting->codec == CCX_CODEC_ATSC_CC)
|
||||
{
|
||||
// Prepare 608 context
|
||||
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
|
||||
setting->settings_608,
|
||||
setting->cc_channel,
|
||||
1,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->output_format,
|
||||
ctx->timing
|
||||
);
|
||||
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
|
||||
setting->settings_608,
|
||||
setting->cc_channel,
|
||||
2,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->output_format,
|
||||
ctx->timing
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->context_cc608_field_1 = NULL;
|
||||
ctx->context_cc608_field_2 = NULL;
|
||||
}
|
||||
ctx->current_field = 1;
|
||||
ctx->private_data = setting->private_data;
|
||||
ctx->fix_padding = setting->fix_padding;
|
||||
ctx->write_format = setting->output_format;
|
||||
ctx->subs_delay = setting->subs_delay;
|
||||
ctx->wbout1 = setting->wbout1;
|
||||
ctx->extract = setting->extract;
|
||||
ctx->fullbin = setting->fullbin;
|
||||
ctx->hauppauge_mode = setting->hauppauge_mode;
|
||||
ctx->program_number = setting->program_number;
|
||||
ctx->processed_enough = 0;
|
||||
ctx->max_gop_length = 0;
|
||||
ctx->has_ccdata_buffered = 0;
|
||||
ctx->in_bufferdatatype = CCX_UNKNOWN;
|
||||
ctx->frames_since_last_gop = 0;
|
||||
memcpy(&ctx->extraction_start, &setting->extraction_start,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&ctx->extraction_end, &setting->extraction_end,sizeof(struct ccx_boundary_time));
|
||||
|
||||
@@ -320,19 +297,96 @@ struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *set
|
||||
else if (setting->output_format==CCX_OF_SMPTETT ||
|
||||
setting->output_format==CCX_OF_SAMI ||
|
||||
setting->output_format==CCX_OF_SRT ||
|
||||
setting->output_format == CCX_OF_WEBVTT ||
|
||||
setting->output_format==CCX_OF_TRANSCRIPT ||
|
||||
setting->output_format==CCX_OF_SPUPNG ||
|
||||
setting->output_format==CCX_OF_SIMPLE_XML ||
|
||||
setting->output_format==CCX_OF_NULL)
|
||||
ctx->writedata = process608;
|
||||
else
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Invalid Write Format Selected");
|
||||
|
||||
memset (&ctx->dec_sub, 0,sizeof(ctx->dec_sub));
|
||||
|
||||
// Initialize HDTV caption buffer
|
||||
init_hdcc(ctx);
|
||||
|
||||
ctx->current_hor_size = 0;
|
||||
ctx->current_vert_size = 0;
|
||||
ctx->current_aspect_ratio = 0;
|
||||
ctx->current_frame_rate = 4; // Assume standard fps, 29.97
|
||||
|
||||
//Variables used while parsing elementry stream
|
||||
ctx->no_bitstream_error = 0;
|
||||
ctx->saw_seqgoppic = 0;
|
||||
ctx->in_pic_data = 0;
|
||||
|
||||
ctx->current_progressive_sequence = 2;
|
||||
ctx->current_pulldownfields = 32768;
|
||||
|
||||
ctx->temporal_reference = 0;
|
||||
ctx->maxtref = 0;
|
||||
ctx->picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
ctx->picture_structure = 0;
|
||||
ctx->top_field_first = 0;
|
||||
ctx->repeat_first_field = 0;
|
||||
ctx->progressive_frame = 0;
|
||||
ctx->pulldownfields = 0;
|
||||
//es parser related variable ends here
|
||||
|
||||
memset(ctx->cc_stats, 0, 4 * sizeof(int));
|
||||
|
||||
ctx->anchor_seq_number = -1;
|
||||
// Init XDS buffers
|
||||
if(setting->ignore_xds == CCX_TRUE)
|
||||
ctx->xds_ctx = NULL;
|
||||
else
|
||||
ctx->xds_ctx = ccx_decoders_xds_init_library(ctx->timing);
|
||||
//xds_cea608_test(ctx->xds_ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
void dinit_cc_decode(struct lib_cc_decode **ctx)
|
||||
|
||||
void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
struct lib_cc_decode *lctx = *ctx;
|
||||
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1);
|
||||
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2);
|
||||
freep(ctx);
|
||||
if(ctx->codec == CCX_CODEC_ATSC_CC)
|
||||
{
|
||||
if (ctx->extract != 2)
|
||||
{
|
||||
if (ctx->write_format==CCX_OF_SMPTETT || ctx->write_format==CCX_OF_SAMI ||
|
||||
ctx->write_format==CCX_OF_SRT || ctx->write_format==CCX_OF_TRANSCRIPT ||
|
||||
ctx->write_format == CCX_OF_WEBVTT || ctx->write_format == CCX_OF_SPUPNG)
|
||||
{
|
||||
flush_608_context(ctx->context_cc608_field_1, sub);
|
||||
}
|
||||
else if(ctx->write_format == CCX_OF_RCWT)
|
||||
{
|
||||
// Write last header and data
|
||||
writercwtdata (ctx, NULL, sub);
|
||||
}
|
||||
}
|
||||
if (ctx->extract != 1)
|
||||
{
|
||||
if (ctx->write_format == CCX_OF_SMPTETT || ctx->write_format == CCX_OF_SAMI ||
|
||||
ctx->write_format == CCX_OF_SRT || ctx->write_format == CCX_OF_TRANSCRIPT ||
|
||||
ctx->write_format == CCX_OF_WEBVTT || ctx->write_format == CCX_OF_SPUPNG)
|
||||
{
|
||||
flush_608_context(ctx->context_cc608_field_2, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ctx->dtvcc->is_active)
|
||||
{
|
||||
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
|
||||
{
|
||||
ccx_dtvcc_service_decoder *decoder = &ctx->dtvcc->decoders[i];
|
||||
if (!ctx->dtvcc->services_active[i])
|
||||
continue;
|
||||
if (decoder->cc_count > 0)
|
||||
{
|
||||
ctx->current_field = 3;
|
||||
ccx_dtvcc_decoder_flush(ctx->dtvcc, decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,21 +7,13 @@
|
||||
#include "ccx_decoders_structs.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
extern unsigned char encoded_crlf[16]; // We keep it encoded here so we don't have to do it many times
|
||||
extern unsigned int encoded_crlf_length;
|
||||
extern unsigned char encoded_br[16];
|
||||
extern unsigned int encoded_br_length;
|
||||
|
||||
extern LLONG minimum_fts; // No screen should start before this FTS
|
||||
|
||||
extern uint64_t utc_refvalue; // UTC referential value
|
||||
|
||||
// Declarations
|
||||
LLONG get_visible_start(void);
|
||||
LLONG get_visible_end(void);
|
||||
LLONG get_visible_start (struct ccx_common_timing_ctx *ctx, int current_field);
|
||||
LLONG get_visible_end (struct ccx_common_timing_ctx *ctx, int current_field);
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank);
|
||||
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding);
|
||||
unsigned int get_decoder_str_basic(unsigned char *buffer, unsigned char *line, int trim_subs, enum ccx_encoding_type encoding);
|
||||
|
||||
void ccx_decoders_common_settings_init(LLONG subs_delay, enum ccx_output_format output_format);
|
||||
|
||||
@@ -32,4 +24,5 @@ void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int lengt
|
||||
const unsigned char *data2, int length2, struct cc_subtitle *sub);
|
||||
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting);
|
||||
void dinit_cc_decode(struct lib_cc_decode **ctx);
|
||||
void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub);
|
||||
#endif
|
||||
|
||||
1419
src/lib_ccx/ccx_decoders_isdb.c
Normal file
1419
src/lib_ccx/ccx_decoders_isdb.c
Normal file
File diff suppressed because it is too large
Load Diff
13
src/lib_ccx/ccx_decoders_isdb.h
Normal file
13
src/lib_ccx/ccx_decoders_isdb.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef ISDB_H
|
||||
#define ISDB_H
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_decoders_structs.h"
|
||||
|
||||
int isdb_set_global_time(struct lib_cc_decode *dec_ctx, uint64_t timestamp);
|
||||
int isdbsub_decode(struct lib_cc_decode *dec_ctx, const uint8_t *buf, size_t buf_size, struct cc_subtitle *sub);
|
||||
void delete_isdb_decoder(void **isdb_ctx);
|
||||
void *init_isdb_decoder(void);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -4,9 +4,14 @@
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_timing.h"
|
||||
|
||||
#include "ccx_common_structs.h"
|
||||
#include "list.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
// Define max width in characters/columns on the screen
|
||||
#define CCX_DECODER_608_SCREEN_WIDTH 32
|
||||
#define MAXBFRAMES 50
|
||||
#define SORTBUF (2*MAXBFRAMES+1)
|
||||
|
||||
|
||||
/* flag raised when end of display marker arrives in Dvb Subtitle */
|
||||
#define SUB_EOD_MARKER (1 << 0 )
|
||||
@@ -81,16 +86,21 @@ struct ccx_decoders_common_settings_t
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
void *wbout1;
|
||||
int cc_to_stdout;
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
int no_rollup;
|
||||
struct ccx_decoder_608_settings *settings_608; // Contains the settings for the 608 decoder.
|
||||
ccx_decoder_dtvcc_settings *settings_dtvcc; //Same for cea 708 captions decoder (dtvcc)
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int trim_subs; // Remove spaces at sides?
|
||||
enum ccx_encoding_type encoding;
|
||||
unsigned send_to_srv;
|
||||
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
int program_number;
|
||||
enum ccx_code_type codec;
|
||||
int ignore_xds;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct lib_cc_decode
|
||||
{
|
||||
int cc_stats[4];
|
||||
@@ -102,14 +112,73 @@ struct lib_cc_decode
|
||||
void *context_cc608_field_1;
|
||||
void *context_cc608_field_2;
|
||||
|
||||
int no_rollup; // If 1, write one line at a time
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
void *wbout1;
|
||||
void *wbout2;
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
struct cc_subtitle dec_sub;
|
||||
enum ccx_bufferdata_type in_bufferdatatype;
|
||||
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
|
||||
int frames_since_last_gop;
|
||||
/* GOP-based timing */
|
||||
int saw_gop_header;
|
||||
/* Time info for timed-transcript */
|
||||
int max_gop_length; // (Maximum) length of a group of pictures
|
||||
int last_gop_length; // Length of the previous group of pictures
|
||||
unsigned total_pulldownfields;
|
||||
unsigned total_pulldownframes;
|
||||
int program_number;
|
||||
struct list_head list;
|
||||
struct ccx_common_timing_ctx *timing;
|
||||
enum ccx_code_type codec;
|
||||
// Set to true if data is buffered
|
||||
int has_ccdata_buffered;
|
||||
|
||||
struct avc_ctx *avc_ctx;
|
||||
void *private_data;
|
||||
|
||||
/* General video information */
|
||||
unsigned int current_hor_size;
|
||||
unsigned int current_vert_size;
|
||||
unsigned int current_aspect_ratio;
|
||||
unsigned int current_frame_rate; // Assume standard fps, 29.97
|
||||
|
||||
/* Reguired in es_function.c */
|
||||
int no_bitstream_error;
|
||||
int saw_seqgoppic;
|
||||
int in_pic_data;
|
||||
|
||||
unsigned int current_progressive_sequence;
|
||||
unsigned int current_pulldownfields ;
|
||||
|
||||
int temporal_reference;
|
||||
enum ccx_frame_type picture_coding_type;
|
||||
unsigned picture_structure;
|
||||
unsigned repeat_first_field;
|
||||
unsigned progressive_frame;
|
||||
unsigned pulldownfields;
|
||||
/* Reguired in es_function.c and es_userdata.c */
|
||||
unsigned top_field_first; // Needs to be global
|
||||
|
||||
ccx_dtvcc_ctx *dtvcc;
|
||||
int current_field;
|
||||
// Analyse/use the picture information
|
||||
int maxtref; // Use to remember the temporal reference number
|
||||
|
||||
int cc_data_count[SORTBUF];
|
||||
// Store fts;
|
||||
LLONG cc_fts[SORTBUF];
|
||||
// Store HD CC packets
|
||||
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
|
||||
|
||||
// The sequence number of the current anchor frame. All currently read
|
||||
// B-Frames belong to this I- or P-frame.
|
||||
int anchor_seq_number;
|
||||
struct ccx_decoders_xds_context *xds_ctx;
|
||||
|
||||
int (*writedata)(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,13 @@
|
||||
#ifndef _XDS_H
|
||||
#define _XDS_H
|
||||
#ifndef CCX_DECODER_XDS_H
|
||||
#define CCX_DECODER_XDS_H
|
||||
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
|
||||
void process_xds_bytes(const unsigned char hi, int lo);
|
||||
void do_end_of_xds(struct cc_subtitle *sub, unsigned char expected_checksum);
|
||||
struct ccx_decoders_xds_context;
|
||||
void process_xds_bytes (struct ccx_decoders_xds_context *ctx, const unsigned char hi, int lo);
|
||||
void do_end_of_xds (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned char expected_checksum);
|
||||
|
||||
void ccx_decoders_xds_init_library(ccx_encoders_transcript_format *transcriptSettings, LLONG subs_delay, char millis_separator);
|
||||
|
||||
void xds_write_transcript_line_suffix (struct ccx_s_write *wb);
|
||||
void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time, LLONG end_time, int cur_xds_packet_class);
|
||||
struct ccx_decoders_xds_context *ccx_decoders_xds_init_library(struct ccx_common_timing_ctx *timing);
|
||||
|
||||
void xds_cea608_test();
|
||||
#endif
|
||||
|
||||
381
src/lib_ccx/ccx_demuxer.c
Normal file
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,15 @@
|
||||
#ifndef _CC_ENCODER_COMMON_H
|
||||
#define _CC_ENCODER_COMMON_H
|
||||
|
||||
#ifdef WIN32
|
||||
#include "..\\win_iconv\\iconv.h"
|
||||
#else
|
||||
#include "iconv.h"
|
||||
#endif
|
||||
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_decoders_structs.h"
|
||||
#include "ccx_encoders_structs.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
#define REQUEST_BUFFER_CAPACITY(ctx,length) if (length>ctx->capacity) \
|
||||
@@ -12,7 +17,12 @@
|
||||
if (ctx->buffer == NULL) { fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
|
||||
}
|
||||
|
||||
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
|
||||
typedef struct ccx_dtvcc_writer_ctx
|
||||
{
|
||||
int fd;
|
||||
char *filename;
|
||||
iconv_t cd;
|
||||
} ccx_dtvcc_writer_ctx;
|
||||
|
||||
/**
|
||||
* Context of encoder, This structure gives single interface
|
||||
@@ -26,32 +36,64 @@ struct encoder_ctx
|
||||
unsigned int capacity;
|
||||
/* keep count of srt subtitle*/
|
||||
unsigned int srt_counter;
|
||||
/* output context */
|
||||
struct ccx_s_write *out;
|
||||
/* start time of previous sub */
|
||||
LLONG prev_start;
|
||||
|
||||
LLONG subs_delay;
|
||||
LLONG last_displayed_subs_ms;
|
||||
int startcredits_displayed;
|
||||
/* Input outputs */
|
||||
/* Flag giving hint that output is send to server through network */
|
||||
unsigned int send_to_srv;
|
||||
/* Used only in Spupng output */
|
||||
int multiple_files;
|
||||
/* Used only in Spupng output and creating name of output file*/
|
||||
char *first_input_file;
|
||||
/* Its array with length of number of languages */
|
||||
struct ccx_s_write *out;
|
||||
/* number of member in array of write out array */
|
||||
int nb_out;
|
||||
/* Input file format used in Teletext for exceptional output */
|
||||
unsigned int in_fileformat; //1 =Normal, 2=Teletext
|
||||
|
||||
/* Flag saying BOM to be written in each output file */
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_date_format date_format;
|
||||
char millis_separator;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
struct ccx_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
int no_bom;
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
int no_font_color;
|
||||
int no_type_setting;
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
unsigned char *subline; // Temp storage for storing each line
|
||||
int extract;
|
||||
|
||||
int dtvcc_extract; //1 or 0 depending if we have to handle dtvcc
|
||||
ccx_dtvcc_writer_ctx dtvcc_writers[CCX_DTVCC_MAX_SERVICES];
|
||||
|
||||
/* Timing related variables*/
|
||||
/* start time of previous sub */
|
||||
LLONG prev_start;
|
||||
LLONG subs_delay;
|
||||
LLONG last_displayed_subs_ms;
|
||||
enum ccx_output_date_format date_format;
|
||||
char millis_separator;
|
||||
|
||||
/* Credit stuff */
|
||||
int startcredits_displayed;
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
unsigned int teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
|
||||
unsigned int send_to_srv;
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
int no_bom;
|
||||
|
||||
// Preencoded strings
|
||||
unsigned char encoded_crlf[16];
|
||||
unsigned int encoded_crlf_length;
|
||||
unsigned char encoded_br[16];
|
||||
unsigned int encoded_br_length;
|
||||
|
||||
int new_sentence; // Capitalize next letter?
|
||||
|
||||
int program_number;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define INITIAL_ENC_BUFFER_CAPACITY 2048
|
||||
@@ -61,13 +103,11 @@ struct encoder_ctx
|
||||
* write subtitle header to file refrenced by
|
||||
* output context
|
||||
*
|
||||
* @param ctx preallocated encoder ctx
|
||||
* @param out output context
|
||||
* @param opt Option to initilaize encoder cfg params
|
||||
* @param cfg Option to initilaize encoder cfg params
|
||||
*
|
||||
* @return 0 on SUCESS, -1 on failure
|
||||
* @return Allocated and properly initilaized Encoder Context, NULL on failure
|
||||
*/
|
||||
int init_encoder(struct encoder_ctx *ctx, struct ccx_s_write *out, struct ccx_s_options *opt);
|
||||
struct encoder_ctx *init_encoder(struct encoder_cfg *opt);
|
||||
|
||||
/**
|
||||
* try to add end credits in subtitle file and then write subtitle
|
||||
@@ -76,9 +116,11 @@ int init_encoder(struct encoder_ctx *ctx, struct ccx_s_write *out, struct ccx_s_
|
||||
* deallocate encoder ctx, so before using encoder_ctx again
|
||||
* after deallocating user need to allocate encoder ctx again
|
||||
*
|
||||
* @oaram ctx Initialized encoder ctx using init_encoder
|
||||
* @oaram arg pointer to initialized encoder ctx using init_encoder
|
||||
*
|
||||
* @param current_fts to calculate window for end credits
|
||||
*/
|
||||
void dinit_encoder(struct encoder_ctx *ctx);
|
||||
void dinit_encoder(struct encoder_ctx **arg, LLONG current_fts);
|
||||
|
||||
/**
|
||||
* @param ctx encoder context
|
||||
@@ -87,17 +129,28 @@ void dinit_encoder(struct encoder_ctx *ctx);
|
||||
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
int write_cc_subtitle_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
|
||||
int write_cc_buffer_as_webvtt(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
int write_cc_subtitle_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_stringz_as_webvtt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
int write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
int write_cc_subtitle_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end);
|
||||
int write_cc_subtitle_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
|
||||
void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *context);
|
||||
|
||||
int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_subtitle_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
|
||||
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_bitmap_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
|
||||
@@ -105,4 +158,9 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
|
||||
void set_encoder_last_displayed_subs_ms(struct encoder_ctx *ctx, LLONG last_displayed_subs_ms);
|
||||
void set_encoder_subs_delay(struct encoder_ctx *ctx, LLONG subs_delay);
|
||||
void set_encoder_startcredits_displayed(struct encoder_ctx *ctx, int startcredits_displayed);
|
||||
void set_encoder_rcwt_fileformat(struct encoder_ctx *ctx, short int format);
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank, int max_len);
|
||||
int get_str_basic(unsigned char *out_buffer, unsigned char *in_buffer, int trim_subs,
|
||||
enum ccx_encoding_type in_enc, enum ccx_encoding_type out_enc, int max_len);
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp stricmp
|
||||
@@ -17,7 +18,6 @@ char **spell_lower = NULL;
|
||||
char **spell_correct = NULL;
|
||||
int spell_words = 0;
|
||||
int spell_capacity = 0;
|
||||
struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
|
||||
// Some basic English words, so user-defined doesn't have to
|
||||
// include the common stuff
|
||||
static const char *spell_builtin[] =
|
||||
@@ -68,9 +68,9 @@ void correct_case(int line_num, struct eia608_screen *data)
|
||||
free(line);
|
||||
}
|
||||
|
||||
void capitalize(int line_num, struct eia608_screen *data)
|
||||
void capitalize(struct encoder_ctx *context, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
|
||||
for (int i = 0; i < CCX_DECODER_608_SCREEN_WIDTH; i++)
|
||||
{
|
||||
switch (data->characters[line_num][i])
|
||||
{
|
||||
@@ -82,14 +82,14 @@ void capitalize(int line_num, struct eia608_screen *data)
|
||||
case '?': // Fallthrough
|
||||
case '!':
|
||||
case ':':
|
||||
new_sentence = 1;
|
||||
context->new_sentence = 1;
|
||||
break;
|
||||
default:
|
||||
if (new_sentence)
|
||||
if (context->new_sentence)
|
||||
data->characters[line_num][i] = cctoupper(data->characters[line_num][i]);
|
||||
else
|
||||
data->characters[line_num][i] = cctolower(data->characters[line_num][i]);
|
||||
new_sentence = 0;
|
||||
context->new_sentence = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -98,12 +98,12 @@ void capitalize(int line_num, struct eia608_screen *data)
|
||||
// Encodes a generic string. Note that since we use the encoders for closed caption
|
||||
// data, text would have to be encoded as CCs... so using special characters here
|
||||
// it's a bad idea.
|
||||
unsigned encode_line(unsigned char *buffer, unsigned char *text)
|
||||
unsigned encode_line(struct encoder_ctx *ctx, unsigned char *buffer, unsigned char *text)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
while (*text)
|
||||
{
|
||||
switch (ccx_encoders_helpers_settings.encoding)
|
||||
switch (ctx->encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
case CCX_ENC_LATIN_1:
|
||||
@@ -120,6 +120,7 @@ unsigned encode_line(unsigned char *buffer, unsigned char *text)
|
||||
}
|
||||
text++;
|
||||
}
|
||||
*buffer = 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -128,7 +129,7 @@ unsigned get_decoder_line_encoded_for_gui(unsigned char *buffer, int line_num, s
|
||||
unsigned char *line = data->characters[line_num];
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
int first = 0, last = 31;
|
||||
find_limit_characters(line, &first, &last);
|
||||
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
|
||||
for (int i = first; i <= last; i++)
|
||||
{
|
||||
get_char_in_latin_1(buffer, line[i]);
|
||||
@@ -139,7 +140,7 @@ unsigned get_decoder_line_encoded_for_gui(unsigned char *buffer, int line_num, s
|
||||
|
||||
}
|
||||
|
||||
unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
|
||||
unsigned char *close_tag(struct encoder_ctx *ctx, unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
|
||||
{
|
||||
for (int l = strlen(tagstack) - 1; l >= 0; l--)
|
||||
{
|
||||
@@ -147,15 +148,15 @@ unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, in
|
||||
switch (cur)
|
||||
{
|
||||
case 'F':
|
||||
buffer += encode_line(buffer, (unsigned char *) "</font>");
|
||||
buffer += encode_line(ctx, buffer, (unsigned char *) "</font>");
|
||||
(*pchanged_font)--;
|
||||
break;
|
||||
case 'U':
|
||||
buffer += encode_line(buffer, (unsigned char *) "</u>");
|
||||
buffer += encode_line(ctx, buffer, (unsigned char *) "</u>");
|
||||
(*punderlined)--;
|
||||
break;
|
||||
case 'I':
|
||||
buffer += encode_line(buffer, (unsigned char *) "</i>");
|
||||
buffer += encode_line(ctx, buffer, (unsigned char *) "</i>");
|
||||
(*pitalics)--;
|
||||
break;
|
||||
}
|
||||
@@ -168,7 +169,7 @@ unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, in
|
||||
return buffer;
|
||||
}
|
||||
|
||||
unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
unsigned get_decoder_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data)
|
||||
{
|
||||
int col = COL_WHITE;
|
||||
int underlined = 0;
|
||||
@@ -179,25 +180,33 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
|
||||
unsigned char *line = data->characters[line_num];
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
int first = 0, last = 31;
|
||||
if (ccx_encoders_helpers_settings.trim_subs)
|
||||
find_limit_characters(line, &first, &last);
|
||||
if (ctx->trim_subs)
|
||||
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
|
||||
for (int i = first; i <= last; i++)
|
||||
{
|
||||
// Handle color
|
||||
int its_col = data->colors[line_num][i];
|
||||
if (its_col != col && !ccx_encoders_helpers_settings.no_font_color &&
|
||||
if (its_col != col && !ctx->no_font_color &&
|
||||
!(col == COL_USERDEFINED && its_col == COL_WHITE)) // Don't replace user defined with white
|
||||
{
|
||||
if (changed_font)
|
||||
buffer = close_tag(buffer, tagstack, 'F', &underlined, &italics, &changed_font);
|
||||
buffer = close_tag(ctx, buffer, tagstack, 'F', &underlined, &italics, &changed_font);
|
||||
|
||||
// Add new font tag
|
||||
buffer += encode_line(buffer, (unsigned char*)color_text[its_col][1]);
|
||||
if ( MAX_COLOR > its_col)
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*)color_text[its_col][1]);
|
||||
else
|
||||
{
|
||||
ccx_common_logging.log_ftn("WARNING:get_decoder_line_encoded:Invalid Color index Selected %d\n", its_col);
|
||||
its_col = COL_WHITE;
|
||||
}
|
||||
|
||||
if (its_col == COL_USERDEFINED)
|
||||
{
|
||||
// The previous sentence doesn't copy the whole
|
||||
// <font> tag, just up to the quote before the color
|
||||
buffer += encode_line(buffer, (unsigned char*)usercolor_rgb);
|
||||
buffer += encode_line(buffer, (unsigned char*) "\">");
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*)usercolor_rgb);
|
||||
buffer += encode_line(ctx, buffer, (unsigned char*) "\">");
|
||||
}
|
||||
if (color_text[its_col][1][0]) // That means a <font> was added to the buffer
|
||||
{
|
||||
@@ -208,30 +217,30 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
|
||||
}
|
||||
// Handle underlined
|
||||
int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
|
||||
if (is_underlined && underlined == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open underline
|
||||
if (is_underlined && underlined == 0 && !ctx->no_type_setting) // Open underline
|
||||
{
|
||||
buffer += encode_line(buffer, (unsigned char *) "<u>");
|
||||
buffer += encode_line(ctx, buffer, (unsigned char *) "<u>");
|
||||
strcat(tagstack, "U");
|
||||
underlined++;
|
||||
}
|
||||
if (is_underlined == 0 && underlined && !ccx_encoders_helpers_settings.no_type_setting) // Close underline
|
||||
if (is_underlined == 0 && underlined && !ctx->no_type_setting) // Close underline
|
||||
{
|
||||
buffer = close_tag(buffer, tagstack, 'U', &underlined, &italics, &changed_font);
|
||||
buffer = close_tag(ctx, buffer, tagstack, 'U', &underlined, &italics, &changed_font);
|
||||
}
|
||||
// Handle italics
|
||||
int has_ita = data->fonts[line_num][i] & FONT_ITALICS;
|
||||
if (has_ita && italics == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open italics
|
||||
if (has_ita && italics == 0 && !ctx->no_type_setting) // Open italics
|
||||
{
|
||||
buffer += encode_line(buffer, (unsigned char *) "<i>");
|
||||
buffer += encode_line(ctx, buffer, (unsigned char *) "<i>");
|
||||
strcat(tagstack, "I");
|
||||
italics++;
|
||||
}
|
||||
if (has_ita == 0 && italics && !ccx_encoders_helpers_settings.no_type_setting) // Close italics
|
||||
if (has_ita == 0 && italics && !ctx->no_type_setting) // Close italics
|
||||
{
|
||||
buffer = close_tag(buffer, tagstack, 'I', &underlined, &italics, &changed_font);
|
||||
buffer = close_tag(ctx, buffer, tagstack, 'I', &underlined, &italics, &changed_font);
|
||||
}
|
||||
int bytes = 0;
|
||||
switch (ccx_encoders_helpers_settings.encoding)
|
||||
switch (ctx->encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
bytes = get_char_in_utf_8(buffer, line[i]);
|
||||
@@ -247,7 +256,7 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
|
||||
}
|
||||
buffer += bytes;
|
||||
}
|
||||
buffer = close_tag(buffer, tagstack, 'A', &underlined, &italics, &changed_font);
|
||||
buffer = close_tag(ctx, buffer, tagstack, 'A', &underlined, &italics, &changed_font);
|
||||
if (underlined || italics || changed_font)
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Not all tags closed in encoding, this is a bug, please report.\n");
|
||||
*buffer = 0;
|
||||
@@ -361,6 +370,9 @@ int add_built_in_words(void)
|
||||
* @param size size of each element
|
||||
* @param compar Comparison function, which is called with three argument
|
||||
* that point to the objects being compared and arg.
|
||||
* compare Funtion should return an integer less than, equal to,
|
||||
* or greater than zero if p1 is found, respectively, to be less than,
|
||||
* to match, or be greater than p2.
|
||||
* @param arg argument passed as it is, to compare function
|
||||
*/
|
||||
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg)
|
||||
@@ -389,9 +401,3 @@ void ccx_encoders_helpers_perform_shellsort_words(void)
|
||||
shell_sort(spell_correct, spell_words, sizeof(*spell_correct), string_cmp2, NULL);
|
||||
}
|
||||
|
||||
void ccx_encoders_helpers_setup(enum ccx_encoding_type encoding,int no_font_color,int no_type_setting,int trim_subs){
|
||||
ccx_encoders_helpers_settings.encoding = encoding;
|
||||
ccx_encoders_helpers_settings.no_font_color = no_font_color;
|
||||
ccx_encoders_helpers_settings.no_type_setting = no_type_setting;
|
||||
ccx_encoders_helpers_settings.trim_subs = trim_subs;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_decoders_structs.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
|
||||
extern char **spell_lower;
|
||||
extern char **spell_correct;
|
||||
@@ -19,18 +20,18 @@ struct ccx_encoders_helpers_settings_t {
|
||||
int no_type_setting;
|
||||
enum ccx_encoding_type encoding;
|
||||
};
|
||||
extern struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
|
||||
|
||||
// Helper functions
|
||||
void correct_case(int line_num, struct eia608_screen *data);
|
||||
void capitalize(int line_num, struct eia608_screen *data);
|
||||
void capitalize(struct encoder_ctx *context, int line_num, struct eia608_screen *data);
|
||||
unsigned get_decoder_line_encoded_for_gui(unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
unsigned get_decoder_line_encoded(struct encoder_ctx *ctx, unsigned char *buffer, int line_num, struct eia608_screen *data);
|
||||
|
||||
int string_cmp(const void *p1, const void *p2);
|
||||
int string_cmp2(const void *p1, const void *p2, void *arg);
|
||||
int add_built_in_words(void);
|
||||
int add_word(const char *word);
|
||||
unsigned encode_line (struct encoder_ctx *ctx, unsigned char *buffer, unsigned char *text);
|
||||
|
||||
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg);
|
||||
|
||||
|
||||
@@ -5,24 +5,47 @@
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
|
||||
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
int write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start);
|
||||
int len = 0;
|
||||
int ret = 0;
|
||||
unsigned char *unescaped = NULL;
|
||||
unsigned char *el = NULL;
|
||||
char str[1024];
|
||||
|
||||
sprintf (str,"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
|
||||
used = encode_line(context->buffer, (unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
used = encode_line(context, context->buffer, (unsigned char *) str);
|
||||
ret = write (context->out->fh, context->buffer, used);
|
||||
if(ret != used)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
len = strlen (string);
|
||||
unescaped= (unsigned char *) malloc (len+1);
|
||||
if(!unescaped)
|
||||
{
|
||||
mprint ("In write_stringz_as_sami() - not enough memory for len %d.\n", len);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el == NULL)
|
||||
{
|
||||
mprint ("In write_stringz_as_sami() - not enough memory for len %d.\n", len);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
@@ -45,16 +68,24 @@ void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_s
|
||||
unsigned char *begin = unescaped;
|
||||
while (begin < unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
unsigned int u = encode_line (context, el, begin);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_br, encoded_br_length);
|
||||
ret = write(context->out->fh, el, u);
|
||||
if(ret != u)
|
||||
goto end;
|
||||
|
||||
ret = write(context->out->fh, context->encoded_br, context->encoded_br_length);
|
||||
if(ret != context->encoded_br_length)
|
||||
goto end;
|
||||
|
||||
ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
if(ret != context->encoded_crlf_length)
|
||||
goto end;
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin += strlen ((const char *) begin) + 1;
|
||||
}
|
||||
|
||||
@@ -63,8 +94,10 @@ void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_s
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line (context->buffer,(unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
used = encode_line (context, context->buffer,(unsigned char *) str);
|
||||
ret = write(context->out->fh, context->buffer, used);
|
||||
if(ret != used)
|
||||
goto end;
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)ms_end);
|
||||
@@ -72,15 +105,21 @@ void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_s
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
write(context->out->fh, context->buffer, used);
|
||||
ret = write(context->out->fh, context->buffer, used);
|
||||
if(ret != used)
|
||||
goto end;
|
||||
|
||||
end:
|
||||
free(el);
|
||||
free(unescaped);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef ENABLE_OCR
|
||||
struct cc_bitmap* rect;
|
||||
LLONG ms_start, ms_end;
|
||||
|
||||
@@ -107,7 +146,6 @@ int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
|
||||
#ifdef ENABLE_OCR
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
@@ -145,11 +183,40 @@ int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int write_cc_subtitle_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cc_subtitle *osub = sub;
|
||||
struct cc_subtitle *lsub = sub;
|
||||
while(sub)
|
||||
{
|
||||
if(sub->type == CC_TEXT)
|
||||
{
|
||||
ret = write_stringz_as_sami(sub->data, context, sub->start_time, sub->end_time);
|
||||
freep(&sub->data);
|
||||
sub->nb_data = 0;
|
||||
}
|
||||
lsub = sub;
|
||||
sub = sub->next;
|
||||
}
|
||||
while(lsub != osub)
|
||||
{
|
||||
sub = lsub->prev;
|
||||
freep(&lsub);
|
||||
lsub = sub;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
LLONG startms, endms;
|
||||
int wrote_something=0;
|
||||
char str[1024];
|
||||
|
||||
startms = data->start_time;
|
||||
|
||||
startms+=context->subs_delay;
|
||||
@@ -158,30 +225,29 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *cont
|
||||
|
||||
endms = data->end_time;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
sprintf (str,"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)startms);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
int length = get_decoder_line_encoded (context, context->subline, i, data);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
|
||||
}
|
||||
write (context->out->fh, subline, length);
|
||||
write (context->out->fh, context->subline, length);
|
||||
wrote_something = 1;
|
||||
if (i!=14)
|
||||
write (context->out->fh, encoded_br, encoded_br_length);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write (context->out->fh, context->encoded_br, context->encoded_br_length);
|
||||
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
@@ -189,7 +255,7 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *cont
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
@@ -198,7 +264,7 @@ int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *cont
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
return wrote_something;
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
|
||||
|
||||
void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
@@ -40,6 +41,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
int pos_r = 0;
|
||||
int pos_w = 0;
|
||||
char str[1024];
|
||||
|
||||
if (el == NULL || unescaped == NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
@@ -52,7 +54,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer, (unsigned char *) str);
|
||||
used = encode_line(context, context->buffer, (unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r < len)
|
||||
@@ -74,16 +76,16 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
unsigned char *begin = unescaped;
|
||||
while (begin < unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
unsigned int u = encode_line (context, el, begin);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n", subline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
//write (wb->fh, encoded_br, encoded_br_length);
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
begin += strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
@@ -92,14 +94,14 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer, (unsigned char *) str);
|
||||
used = encode_line(context, context->buffer, (unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str, "<p begin=\"%02u:%02u:%02u.%03u\">\n\n", h2, m2, s2, ms2);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer, (unsigned char *) str);
|
||||
used = encode_line(context, context->buffer, (unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str, "</p>\n");
|
||||
free(el);
|
||||
@@ -110,6 +112,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef ENABLE_OCR
|
||||
struct cc_bitmap* rect;
|
||||
LLONG ms_start, ms_end;
|
||||
//char timeline[128];
|
||||
@@ -139,7 +142,6 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
|
||||
#ifdef ENABLE_OCR
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
@@ -153,7 +155,7 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
|
||||
write (context->out->fh, buf,strlen(buf) );
|
||||
len = strlen(rect[0].ocr_text);
|
||||
write (context->out->fh, rect[0].ocr_text, len);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
sprintf ( buf,"</p>\n");
|
||||
write (context->out->fh, buf,strlen(buf) );
|
||||
|
||||
@@ -167,6 +169,33 @@ int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *cont
|
||||
|
||||
}
|
||||
|
||||
int write_cc_subtitle_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cc_subtitle *osub = sub;
|
||||
struct cc_subtitle *lsub = sub;
|
||||
while(sub)
|
||||
{
|
||||
if(sub->type == CC_TEXT)
|
||||
{
|
||||
write_stringz_as_smptett(sub->data, context, sub->start_time, sub->end_time);
|
||||
freep(&sub->data);
|
||||
sub->nb_data = 0;
|
||||
}
|
||||
lsub = sub;
|
||||
sub = sub->next;
|
||||
}
|
||||
while(lsub != osub)
|
||||
{
|
||||
sub = lsub->prev;
|
||||
freep(&lsub);
|
||||
lsub = sub;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
@@ -175,6 +204,7 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
|
||||
LLONG endms;
|
||||
int wrote_something=0;
|
||||
LLONG startms = data->start_time;
|
||||
char str[1024];
|
||||
|
||||
startms+=context->subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
@@ -191,22 +221,22 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0; i < 15; i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
int length = get_decoder_line_encoded (context, context->subline, i, data);
|
||||
if (context->encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
|
||||
}
|
||||
write(context->out->fh, subline, length);
|
||||
write(context->out->fh, context->subline, length);
|
||||
wrote_something=1;
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
@@ -214,14 +244,14 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
|
||||
if (context->encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) str);
|
||||
//write (wb->fh, enc_buffer,enc_buffer_used);
|
||||
|
||||
return wrote_something;
|
||||
@@ -1,7 +1,24 @@
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include "608_spupng.h"
|
||||
#include "ccx_encoders_spupng.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
|
||||
void draw_str(char *str, uint8_t * canvas, int rowstride)
|
||||
{
|
||||
char *ptr;
|
||||
uint8_t* cell;
|
||||
uint8_t pen[2];
|
||||
int i = 0;
|
||||
pen[0] = COL_BLACK;
|
||||
pen[1] = COL_WHITE;
|
||||
for(ptr = str; ptr != '\0';ptr++)
|
||||
{
|
||||
cell = canvas + ((i+1) * CCW);
|
||||
draw_char_indexed(cell, rowstride, pen, 0, 0, 0);
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
void draw_row(struct eia608_screen* data, int row, uint8_t * canvas, int rowstride)
|
||||
{
|
||||
int column;
|
||||
@@ -181,6 +198,76 @@ int spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
|
||||
|
||||
write_error:
|
||||
|
||||
unknown_error:
|
||||
free (row_pointer);
|
||||
|
||||
free (image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spupng_export_string2png(struct spupng_t *sp, char *str)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytep *row_pointer;
|
||||
png_bytep image;
|
||||
int ww, wh, rowstride, row_adv;
|
||||
int row = 0;
|
||||
|
||||
assert ((sizeof(png_byte) == sizeof(uint8_t))
|
||||
&& (sizeof(*image) == sizeof(uint8_t)));
|
||||
|
||||
// Allow space at beginning and end of each row for a padding space
|
||||
ww = CCW * (COLUMNS+2);
|
||||
wh = CCH * ROWS;
|
||||
row_adv = (COLUMNS+2) * CCW * CCH;
|
||||
|
||||
rowstride = ww * sizeof(*image);
|
||||
|
||||
if (!(row_pointer = (png_bytep*)malloc(sizeof(*row_pointer) * wh))) {
|
||||
mprint("Unable to allocate %d byte buffer.\n",
|
||||
sizeof(*row_pointer) * wh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(image = (png_bytep)malloc(wh * ww * sizeof(*image)))) {
|
||||
mprint("Unable to allocate %d KB image buffer.",
|
||||
wh * ww * sizeof(*image) / 1024);
|
||||
free(row_pointer);
|
||||
return 0;
|
||||
}
|
||||
// Initialize image to transparent
|
||||
memset(image, COL_TRANSPARENT, wh * ww * sizeof(*image));
|
||||
|
||||
/* draw the image */
|
||||
draw_str(str, image + row * row_adv, rowstride);
|
||||
|
||||
/* Now save the image */
|
||||
|
||||
if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL, NULL, NULL)))
|
||||
goto unknown_error;
|
||||
|
||||
if (!(info_ptr = png_create_info_struct(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
|
||||
goto unknown_error;
|
||||
}
|
||||
#if 0
|
||||
if (!spupng_write_png (sp, data, png_ptr, info_ptr, image, row_pointer, ww, wh)) {
|
||||
png_destroy_write_struct (&png_ptr, &info_ptr);
|
||||
goto write_error;
|
||||
}
|
||||
#endif
|
||||
png_destroy_write_struct (&png_ptr, &info_ptr);
|
||||
|
||||
free (row_pointer);
|
||||
|
||||
free (image);
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
unknown_error:
|
||||
free (row_pointer);
|
||||
|
||||
@@ -196,6 +283,7 @@ int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
int row;
|
||||
int empty_buf = 1;
|
||||
char str[256] = "";
|
||||
int str_len = 0;
|
||||
LLONG ms_start = data->start_time + context->subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
@@ -235,11 +323,11 @@ int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
{
|
||||
if (data->row_used[row])
|
||||
{
|
||||
int len = get_decoder_line_encoded(subline, row, data);
|
||||
int len = get_decoder_line_encoded(context, context->subline, row, data);
|
||||
// Check for characters that spumux won't parse
|
||||
// null chars will be changed to space
|
||||
// pairs of dashes will be changed to underscores
|
||||
for (unsigned char* ptr = subline; ptr < subline+len; ptr++)
|
||||
for (unsigned char* ptr = context->subline; ptr < context->subline+len; ptr++)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
@@ -255,14 +343,66 @@ int spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
break;
|
||||
}
|
||||
}
|
||||
strncat(str,(const char*)subline,256);
|
||||
strncat(str,"\n",256);
|
||||
if (str_len + len + 3 > 256 )
|
||||
{
|
||||
mprint("WARNING: Possible Loss of data\n");
|
||||
break;
|
||||
}
|
||||
strncat(str, (const char*)context->subline, len);
|
||||
strncat(str,"\n",3);
|
||||
str_len = str_len + len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
write_spucomment(sp,str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spupng_write_string(struct spupng_t *sp, char *string, LLONG start_time, LLONG end_time,
|
||||
struct encoder_ctx *context)
|
||||
{
|
||||
|
||||
char str[256] = "";
|
||||
LLONG ms_start = start_time + context->subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LLONG ms_end = end_time;
|
||||
|
||||
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
|
||||
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
if (!spupng_export_string2png(sp, str))
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
|
||||
sp->pngfile, strerror(errno));
|
||||
}
|
||||
fclose(sp->fppng);
|
||||
write_sputag(sp,ms_start,ms_end);
|
||||
write_spucomment(sp,str);
|
||||
return 1;
|
||||
}
|
||||
int write_cc_subtitle_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
|
||||
if (!sp)
|
||||
return -1;
|
||||
|
||||
if(sub->type == CC_TEXT)
|
||||
{
|
||||
spupng_write_string(sp, sub->data, sub->start_time, sub->end_time, context);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *) context->out->spupng_data;
|
||||
@@ -2,25 +2,30 @@
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
#include "ocr.h"
|
||||
|
||||
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
|
||||
if there is any */
|
||||
void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
char timeline[128];
|
||||
|
||||
if(!string || !string[0])
|
||||
return 0;
|
||||
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u%s", context->srt_counter, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption - - -\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
|
||||
|
||||
@@ -52,36 +57,39 @@ void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_st
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
unsigned int u = encode_line (context, el, begin);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
free(el);
|
||||
free(unescaped);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef ENABLE_OCR
|
||||
struct cc_bitmap* rect;
|
||||
LLONG ms_start, ms_end;
|
||||
#ifdef ENABLE_OCR
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
char timeline[128];
|
||||
int len = 0;
|
||||
int used;
|
||||
#endif
|
||||
int i = 0;
|
||||
char *str;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
@@ -105,9 +113,8 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
if(sub->flags & SUB_EOD_MARKER)
|
||||
context->prev_start = sub->start_time;
|
||||
|
||||
rect = sub->data;
|
||||
#ifdef ENABLE_OCR
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
str = paraof_ocrtext(sub);
|
||||
if (str)
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
@@ -115,16 +122,22 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
len = strlen(rect[0].ocr_text);
|
||||
write (context->out->fh, rect[0].ocr_text, len);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
len = strlen(str);
|
||||
write (context->out->fh, str, len);
|
||||
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
}
|
||||
freep(&str);
|
||||
}
|
||||
for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++)
|
||||
{
|
||||
freep(rect->data);
|
||||
freep(rect->data+1);
|
||||
}
|
||||
#endif
|
||||
sub->nb_data = 0;
|
||||
@@ -132,6 +145,33 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int write_cc_subtitle_as_srt(struct cc_subtitle *sub,struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cc_subtitle *osub = sub;
|
||||
struct cc_subtitle *lsub = sub;
|
||||
|
||||
while(sub)
|
||||
{
|
||||
if(sub->type == CC_TEXT)
|
||||
{
|
||||
ret = write_stringz_as_srt(sub->data, context, sub->start_time, sub->end_time);
|
||||
freep(&sub->data);
|
||||
sub->nb_data = 0;
|
||||
}
|
||||
lsub = sub;
|
||||
sub = sub->next;
|
||||
}
|
||||
while(lsub != osub)
|
||||
{
|
||||
sub = lsub->prev;
|
||||
freep(&lsub);
|
||||
lsub = sub;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
@@ -165,12 +205,12 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u%s", context->srt_counter, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer,(unsigned char *) timeline);
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
|
||||
@@ -182,7 +222,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
{
|
||||
if (context->sentence_cap)
|
||||
{
|
||||
capitalize (i,data);
|
||||
capitalize (context, i, data);
|
||||
correct_case(i,data);
|
||||
}
|
||||
if (context->autodash && context->trim_subs)
|
||||
@@ -190,7 +230,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
int first=0, last=31, center1=-1, center2=-1;
|
||||
unsigned char *line = data->characters[i];
|
||||
int do_dash=1, colon_pos=-1;
|
||||
find_limit_characters(line,&first,&last);
|
||||
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
|
||||
if (first==-1 || last==-1) // Probably a bug somewhere though
|
||||
break;
|
||||
// Is there a speaker named, for example: TOM: What are you doing?
|
||||
@@ -242,21 +282,21 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
prev_line_center2=center2;
|
||||
|
||||
}
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
int length = get_decoder_line_encoded (context, context->subline, i, data);
|
||||
if (context->encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
|
||||
}
|
||||
write(context->out->fh, subline, length);
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write(context->out->fh, context->subline, length);
|
||||
write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
wrote_something=1;
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
// fprintf (wb->fh,context->encoded_crlf);
|
||||
}
|
||||
}
|
||||
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
// fprintf (wb->fh, encoded_crlf);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
// fprintf (wb->fh, context->encoded_crlf);
|
||||
write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
return wrote_something;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#ifndef CCX_ENCODERS_STRUCTS_H
|
||||
#define CCX_ENCODERS_STRUCTS_H
|
||||
|
||||
typedef struct ccx_encoders_transcript_format {
|
||||
// TODO: add more options, and (perhaps) reduce other ccextractor options?
|
||||
@@ -14,12 +15,9 @@ typedef struct ccx_encoders_transcript_format {
|
||||
|
||||
struct ccx_s_write
|
||||
{
|
||||
int multiple_files;
|
||||
char *first_input_file;
|
||||
int fh;
|
||||
char *filename;
|
||||
void* spupng_data;
|
||||
};
|
||||
|
||||
#define CCX_ENCODERS_STRUCTS_H
|
||||
#endif
|
||||
|
||||
272
src/lib_ccx/ccx_encoders_webvtt.c
Normal file
272
src/lib_ccx/ccx_encoders_webvtt.c
Normal file
@@ -0,0 +1,272 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
|
||||
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
|
||||
if there is any */
|
||||
int write_stringz_as_webvtt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
unsigned h1, m1, s1, ms1;
|
||||
unsigned h2, m2, s2, ms2;
|
||||
int written;
|
||||
char timeline[128];
|
||||
|
||||
mstotime(ms_start, &h1, &m1, &s1, &ms1);
|
||||
mstotime(ms_end - 1, &h2, &m2, &s2, &ms2); // -1 To prevent overlapping with next line.
|
||||
|
||||
|
||||
used = encode_line(context, context->buffer, (unsigned char *)timeline);
|
||||
written = write(context->out->fh, context->buffer, used);
|
||||
if (written != used)
|
||||
return -1;
|
||||
sprintf(timeline, "%02u:%02u:%02u.%03u --> %02u:%02u:%02u.%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer, (unsigned char *)timeline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - WEBVTT caption - - -\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s", timeline);
|
||||
|
||||
written = write(context->out->fh, context->buffer, used);
|
||||
if (written != used)
|
||||
return -1;
|
||||
int len = strlen(string);
|
||||
unsigned char *unescaped = (unsigned char *)malloc(len + 1);
|
||||
unsigned char *el = (unsigned char *)malloc(len * 3 + 1); // Be generous
|
||||
if (el == NULL || unescaped == NULL)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_webvtt() - not enough memory.\n");
|
||||
int pos_r = 0;
|
||||
int pos_w = 0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r] == '\\' && string[pos_r + 1] == 'n')
|
||||
{
|
||||
unescaped[pos_w] = 0;
|
||||
pos_r += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w] = string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w] = 0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin = unescaped;
|
||||
while (begin<unescaped + len)
|
||||
{
|
||||
unsigned int u = encode_line(context, el, begin);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
|
||||
}
|
||||
written = write(context->out->fh, el, u);
|
||||
if (written != u)
|
||||
{
|
||||
free(el);
|
||||
free(unescaped);
|
||||
return -1;
|
||||
}
|
||||
written = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
if (written != context->encoded_crlf_length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
begin += strlen((const char *)begin) + 1;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
written = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
free(el);
|
||||
free(unescaped);
|
||||
if (written != context->encoded_crlf_length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_cc_bitmap_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
//TODO
|
||||
int ret = 0;
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_cc_subtitle_as_webvtt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cc_subtitle *osub = sub;
|
||||
struct cc_subtitle *lsub = sub;
|
||||
|
||||
while (sub)
|
||||
{
|
||||
if (sub->type == CC_TEXT)
|
||||
{
|
||||
ret = write_stringz_as_webvtt(sub->data, context, sub->start_time, sub->end_time);
|
||||
freep(&sub->data);
|
||||
sub->nb_data = 0;
|
||||
}
|
||||
lsub = sub;
|
||||
sub = sub->next;
|
||||
}
|
||||
while (lsub != osub)
|
||||
{
|
||||
sub = lsub->prev;
|
||||
freep(&lsub);
|
||||
lsub = sub;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
int write_cc_buffer_as_webvtt(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
int written;
|
||||
unsigned h1, m1, s1, ms1;
|
||||
unsigned h2, m2, s2, ms2;
|
||||
LLONG ms_start, ms_end;
|
||||
int wrote_something = 0;
|
||||
ms_start = data->start_time;
|
||||
|
||||
int prev_line_start = -1, prev_line_end = -1; // Column in which the previous line started and ended, for autodash
|
||||
int prev_line_center1 = -1, prev_line_center2 = -1; // Center column of previous line text
|
||||
int empty_buf = 1;
|
||||
char timeline[128] = "";
|
||||
for (int i = 0; i<15; i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
empty_buf = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty_buf) // Prevent writing empty screens. Not needed in .vtt
|
||||
return 0;
|
||||
|
||||
ms_start += context->subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
ms_end = data->end_time;
|
||||
|
||||
mstotime(ms_start, &h1, &m1, &s1, &ms1);
|
||||
mstotime(ms_end - 1, &h2, &m2, &s2, &ms2); // -1 To prevent overlapping with next line.
|
||||
|
||||
sprintf(timeline, "%02u:%02u:%02u.%03u --> %02u:%02u:%02u.%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
|
||||
used = encode_line(context, context->buffer, (unsigned char *)timeline);
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - WEBVTT caption - - -\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s", timeline);
|
||||
|
||||
written = write(context->out->fh, context->buffer, used);
|
||||
if (written != used)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i<15; i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
if (context->sentence_cap)
|
||||
{
|
||||
capitalize(context, i, data);
|
||||
correct_case(i, data);
|
||||
}
|
||||
if (context->autodash && context->trim_subs)
|
||||
{
|
||||
int first = 0, last = 31, center1 = -1, center2 = -1;
|
||||
unsigned char *line = data->characters[i];
|
||||
int do_dash = 1, colon_pos = -1;
|
||||
find_limit_characters(line, &first, &last, CCX_DECODER_608_SCREEN_WIDTH);
|
||||
if (first == -1 || last == -1) // Probably a bug somewhere though
|
||||
break;
|
||||
// Is there a speaker named, for example: TOM: What are you doing?
|
||||
for (int j = first; j <= last; j++)
|
||||
{
|
||||
if (line[j] == ':')
|
||||
{
|
||||
colon_pos = j;
|
||||
break;
|
||||
}
|
||||
if (!isupper(line[j]))
|
||||
break;
|
||||
}
|
||||
if (prev_line_start == -1)
|
||||
do_dash = 0;
|
||||
if (first == prev_line_start) // Case of left alignment
|
||||
do_dash = 0;
|
||||
if (last == prev_line_end) // Right align
|
||||
do_dash = 0;
|
||||
if (first>prev_line_start && last<prev_line_end) // Fully contained
|
||||
do_dash = 0;
|
||||
if ((first>prev_line_start && first<prev_line_end) || // Overlap
|
||||
(last>prev_line_start && last<prev_line_end))
|
||||
do_dash = 0;
|
||||
|
||||
center1 = (first + last) / 2;
|
||||
if (colon_pos != -1)
|
||||
{
|
||||
while (colon_pos<CCX_DECODER_608_SCREEN_WIDTH &&
|
||||
(line[colon_pos] == ':' ||
|
||||
line[colon_pos] == ' ' ||
|
||||
line[colon_pos] == 0x89))
|
||||
colon_pos++; // Find actual text
|
||||
center2 = (colon_pos + last) / 2;
|
||||
}
|
||||
else
|
||||
center2 = center1;
|
||||
|
||||
if (center1 >= prev_line_center1 - 1 && center1 <= prev_line_center1 + 1 && center1 != -1) // Center align
|
||||
do_dash = 0;
|
||||
if (center2 >= prev_line_center2 - 2 && center1 <= prev_line_center2 + 2 && center1 != -1) // Center align
|
||||
do_dash = 0;
|
||||
|
||||
if (do_dash)
|
||||
{
|
||||
written = write(context->out->fh, "- ", 2);
|
||||
if (written != 2)
|
||||
return -1;
|
||||
}
|
||||
prev_line_start = first;
|
||||
prev_line_end = last;
|
||||
prev_line_center1 = center1;
|
||||
prev_line_center2 = center2;
|
||||
|
||||
}
|
||||
int length = get_decoder_line_encoded(context, context->subline, i, data);
|
||||
if (context->encoding != CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
|
||||
}
|
||||
written = write(context->out->fh, context->subline, length);
|
||||
if (written != length)
|
||||
return -1;
|
||||
written = write(context->out->fh,
|
||||
context->encoded_crlf, context->encoded_crlf_length);
|
||||
if (written != context->encoded_crlf_length)
|
||||
return -1;
|
||||
wrote_something = 1;
|
||||
// fprintf (wb->fh,encoded_crlf);
|
||||
}
|
||||
}
|
||||
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
// fprintf (wb->fh, encoded_crlf);
|
||||
written = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
|
||||
if (written != context->encoded_crlf_length)
|
||||
return -1;
|
||||
|
||||
return wrote_something;
|
||||
}
|
||||
95
src/lib_ccx/ccx_encoders_xds.c
Normal file
95
src/lib_ccx/ccx_encoders_xds.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
|
||||
static const char *XDSclasses_short[]=
|
||||
{
|
||||
"CUR",
|
||||
"FUT",
|
||||
"CHN",
|
||||
"MIS",
|
||||
"PUB",
|
||||
"RES",
|
||||
"PRV",
|
||||
"END"
|
||||
};
|
||||
|
||||
void xds_write_transcript_line_prefix (struct encoder_ctx *context, struct ccx_s_write *wb, LLONG start_time, LLONG end_time, int cur_xds_packet_class)
|
||||
{
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
if (!wb || wb->fh==-1)
|
||||
return;
|
||||
|
||||
if (start_time == -1)
|
||||
{
|
||||
// Means we entered XDS mode without making a note of the XDS start time. This is a bug.
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
|
||||
}
|
||||
|
||||
if (context->transcript_settings->showStartTime)
|
||||
{
|
||||
char buffer[80];
|
||||
if (context->transcript_settings->relativeTimestamp)
|
||||
{
|
||||
if (utc_refvalue == UINT64_MAX)
|
||||
{
|
||||
mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
|
||||
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h1, m1, s1, context->millis_separator, ms1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fdprintf(wb->fh, "%lld%c%03d|", (start_time + context->subs_delay) / 1000,
|
||||
context->millis_separator, (start_time + context->subs_delay) % 1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + context->subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + context->subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(wb->fh, "%s%c%03d|", buffer, context->millis_separator, start_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (context->transcript_settings->showEndTime)
|
||||
{
|
||||
char buffer[80];
|
||||
if (context->transcript_settings->relativeTimestamp)
|
||||
{
|
||||
if (utc_refvalue == UINT64_MAX)
|
||||
{
|
||||
mstotime(end_time, &h2, &m2, &s2, &ms2);
|
||||
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h2, m2, s2, context->millis_separator, ms2);
|
||||
}
|
||||
else
|
||||
{
|
||||
fdprintf(wb->fh, "%lld%s%03d|", end_time / 1000, context->millis_separator, end_time% 1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mstotime(end_time, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = end_time / 1000;
|
||||
int end_time_dec = end_time % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", end_time_struct);
|
||||
fdprintf(wb->fh, "%s%c%03d|", buffer, context->millis_separator, end_time_dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (context->transcript_settings->showMode)
|
||||
{
|
||||
const char *mode = "XDS";
|
||||
fdprintf(wb->fh, "%s|", mode);
|
||||
}
|
||||
|
||||
if (context->transcript_settings->showCC)
|
||||
{
|
||||
fdprintf(wb->fh, "%s|", XDSclasses_short[cur_xds_packet_class]);
|
||||
}
|
||||
}
|
||||
|
||||
5
src/lib_ccx/ccx_encoders_xds.h
Normal file
5
src/lib_ccx/ccx_encoders_xds.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#ifndef _CCX_ENCODER_XDS_H
|
||||
#define _CCX_ENCODER_XDS_H
|
||||
|
||||
void xds_write_transcript_line_prefix (struct encoder_ctx *context, struct ccx_s_write *wb, LLONG start_time, LLONG end_time, int cur_xds_packet_class);
|
||||
#endif
|
||||
@@ -2,10 +2,6 @@
|
||||
#define CXX_MP4_H
|
||||
|
||||
|
||||
struct ccx_s_mp4Cfg
|
||||
{
|
||||
unsigned int mp4vidtrack :1;
|
||||
};
|
||||
|
||||
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file,void *enc_ctx);
|
||||
int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file);
|
||||
#endif
|
||||
|
||||
@@ -47,28 +47,13 @@ struct conf_map configuration_map[] = {
|
||||
{"BUFFER_INPUT",offsetof(struct ccx_s_options,buffer_input),set_int},
|
||||
{"NOFONT_COLOR",offsetof(struct ccx_s_options,nofontcolor),set_int},
|
||||
{"NOTYPE_SETTING",offsetof(struct ccx_s_options,notypesetting),set_int},
|
||||
{"CODEC",offsetof(struct ccx_s_options,codec),set_int},
|
||||
{"NOCODEC",offsetof(struct ccx_s_options,nocodec),set_int},
|
||||
{"OUTPUT_FORMAT",offsetof(struct ccx_s_options,write_format),set_int},
|
||||
{"START_CREDIT_TEXT",offsetof(struct ccx_s_options,start_credits_text),set_string},
|
||||
{"START_CREDIT_NOT_BEFORE",offsetof(struct ccx_s_options,startcreditsnotbefore),set_time},
|
||||
{"START_CREDIT_NOT_AFTER",offsetof(struct ccx_s_options,startcreditsnotafter),set_time},
|
||||
{"START_CREDIT_FOR_ATLEAST",offsetof(struct ccx_s_options,startcreditsforatleast),set_time},
|
||||
{"START_CREDIT_FOR_ATMOST",offsetof(struct ccx_s_options,startcreditsforatmost),set_time},
|
||||
{"END_CREDITS_TEXT",offsetof(struct ccx_s_options,end_credits_text),set_string},
|
||||
{"END_CREDITS_FOR_ATLEAST",offsetof(struct ccx_s_options,endcreditsforatleast),set_time},
|
||||
{"END_CREDITS_FOR_ATMOST",offsetof(struct ccx_s_options,endcreditsforatmost),set_time},
|
||||
{"VIDEO_EDITED",offsetof(struct ccx_s_options,binary_concat),set_int},
|
||||
{"GOP_TIME",offsetof(struct ccx_s_options,use_gop_as_pts),set_int},
|
||||
{"FIX_PADDINDG",offsetof(struct ccx_s_options,fix_padding),set_int},
|
||||
{"TRIM",offsetof(struct ccx_s_options,trim_subs),set_int},
|
||||
{"GUI_MODE_REPORTS",offsetof(struct ccx_s_options,gui_mode_reports),set_int},
|
||||
{"NO_PROGRESS_BAR",offsetof(struct ccx_s_options,no_progress_bar),set_int},
|
||||
{"SENTENCE_CAP",offsetof(struct ccx_s_options,sentence_cap),set_int},
|
||||
{"CAP_FILE",offsetof(struct ccx_s_options,sentence_cap_file),set_string},
|
||||
{"PROGRAM_NUMBER",offsetof(struct ccx_s_options,ts_forced_program),set_int},
|
||||
{"AUTO_PROGRAM",offsetof(struct ccx_s_options,ts_autoprogram),set_int},
|
||||
{"STREAM",offsetof(struct ccx_s_options,live_stream),set_int},
|
||||
{"START_AT",offsetof(struct ccx_s_options,extraction_start),set_time},
|
||||
{"END_AT",offsetof(struct ccx_s_options,extraction_end),set_time},
|
||||
{"INVASTIGATE_PACKET",offsetof(struct ccx_s_options,investigate_packets),set_int},
|
||||
@@ -76,15 +61,9 @@ struct conf_map configuration_map[] = {
|
||||
{"NO_SYNC",offsetof(struct ccx_s_options,nosync),set_int},
|
||||
{"HAUPPAUGE_MODE",offsetof(struct ccx_s_options,hauppauge_mode),set_int},
|
||||
{"MP4_VIDEO_TRACK",offsetof(struct ccx_s_options,mp4vidtrack),set_int},
|
||||
{"ENCODING",offsetof(struct ccx_s_options,encoding),set_int},
|
||||
{"USE_PIC_ORDER",offsetof(struct ccx_s_options,usepicorder),set_int},
|
||||
{"AUTO_MYTH",offsetof(struct ccx_s_options,auto_myth),set_int},
|
||||
{"WTV_MPEG2",offsetof(struct ccx_s_options,wtvmpeg2),set_int},
|
||||
{"OUTPUT_FILENAME",offsetof(struct ccx_s_options,output_filename),set_string},
|
||||
{"OUT_ELEMENTRY_STREAM_FILENAME",offsetof(struct ccx_s_options,out_elementarystream_filename),set_string},
|
||||
{"DATA_PID",offsetof(struct ccx_s_options,ts_cappid),set_int},
|
||||
{"STREAM_TYPE",offsetof(struct ccx_s_options,ts_datastreamtype),set_int},
|
||||
{"TS_FORCED_STREAM_TYPE",offsetof(struct ccx_s_options,ts_forced_streamtype),set_int},
|
||||
{"DATE_FORMAT",offsetof(struct ccx_s_options,date_format),set_int},
|
||||
// Settings for 608 decoder
|
||||
{ "NO_ROLL_UP", offsetof(struct ccx_s_options, settings_608.no_rollup), set_int },
|
||||
|
||||
@@ -429,9 +429,18 @@ void* dvbsub_init_decoder(struct dvb_config* cfg)
|
||||
DVBSubContext *ctx = (DVBSubContext*) malloc(sizeof(DVBSubContext));
|
||||
memset(ctx, 0, sizeof(DVBSubContext));
|
||||
|
||||
ctx->composition_id = cfg->composition_id[0];
|
||||
ctx->ancillary_id = cfg->ancillary_id[0];
|
||||
ctx->lang_index = cfg->lang_index[0];
|
||||
if(cfg)
|
||||
{
|
||||
ctx->composition_id = cfg->composition_id[0];
|
||||
ctx->ancillary_id = cfg->ancillary_id[0];
|
||||
ctx->lang_index = cfg->lang_index[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->composition_id = 1;
|
||||
ctx->ancillary_id = 1;
|
||||
ctx->lang_index = 1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OCR
|
||||
ctx->ocr_ctx = init_ocr(ctx->lang_index);
|
||||
@@ -522,9 +531,9 @@ void* dvbsub_init_decoder(struct dvb_config* cfg)
|
||||
|
||||
return (void*) ctx;
|
||||
}
|
||||
int dvbsub_close_decoder(void *dvb_ctx)
|
||||
int dvbsub_close_decoder(void **dvb_ctx)
|
||||
{
|
||||
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
|
||||
DVBSubContext *ctx = (DVBSubContext *) *dvb_ctx;
|
||||
DVBSubRegionDisplay *display;
|
||||
|
||||
delete_regions(ctx);
|
||||
@@ -542,6 +551,10 @@ int dvbsub_close_decoder(void *dvb_ctx)
|
||||
free(display);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OCR
|
||||
delete_ocr(&ctx->ocr_ctx);
|
||||
#endif
|
||||
freep(dvb_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1427,20 +1440,29 @@ static void dvbsub_parse_display_definition_segment(void *dvb_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
/**
|
||||
* Write Subtitle in cc_subtitle structure in CC_BITMAP format
|
||||
* when OCR subsystem is present then it also write recognised text in
|
||||
* cc_bitmap ocr_text variable.
|
||||
*/
|
||||
static int write_dvb_sub(struct lib_cc_decode *dec_ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
|
||||
DVBSubContext *ctx;
|
||||
DVBSubRegion *region;
|
||||
DVBSubRegionDisplay *display;
|
||||
DVBSubCLUT *clut;
|
||||
DVBSubDisplayDefinition *display_def = ctx->display_definition;
|
||||
DVBSubDisplayDefinition *display_def;
|
||||
struct cc_bitmap *rect = NULL;
|
||||
uint32_t *clut_table;
|
||||
int offset_x=0, offset_y=0;
|
||||
int ret = 0;
|
||||
|
||||
ctx = (DVBSubContext *) dec_ctx->private_data;
|
||||
|
||||
display_def = ctx->display_definition;
|
||||
sub->type = CC_BITMAP;
|
||||
sub->lang_index = ctx->lang_index;
|
||||
|
||||
if (display_def)
|
||||
{
|
||||
offset_x = display_def->x;
|
||||
@@ -1464,7 +1486,8 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
return -1;
|
||||
}
|
||||
|
||||
sub->start_time = get_visible_start();
|
||||
/* USE PTS and convert here in required time */
|
||||
sub->start_time = get_visible_start(dec_ctx->timing, 1);
|
||||
sub->end_time = sub->start_time + ( ctx->time_out * 1000 );
|
||||
sub->flags |= SUB_EOD_MARKER;
|
||||
sub->got_output = 1;
|
||||
@@ -1521,12 +1544,6 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
rect++;
|
||||
|
||||
}
|
||||
#ifdef DeBUG
|
||||
if (ctx->object_list)
|
||||
{
|
||||
//save_display_set(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1539,9 +1556,9 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
*
|
||||
* @return -1 on error
|
||||
*/
|
||||
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub)
|
||||
int dvbsub_decode(struct lib_cc_decode *dec_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub)
|
||||
{
|
||||
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
|
||||
DVBSubContext *ctx = (DVBSubContext *) dec_ctx->private_data;
|
||||
const uint8_t *p, *p_end;
|
||||
int segment_type;
|
||||
int page_id;
|
||||
@@ -1558,7 +1575,9 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
|
||||
p = buf;
|
||||
p_end = buf + buf_size;
|
||||
|
||||
set_fts();
|
||||
dec_ctx->timing->current_tref = 0;
|
||||
set_fts(dec_ctx->timing);
|
||||
|
||||
while (p_end - p >= 6 && *p == 0x0f)
|
||||
{
|
||||
p += 1;
|
||||
@@ -1580,29 +1599,29 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
|
||||
switch (segment_type)
|
||||
{
|
||||
case DVBSUB_PAGE_SEGMENT:
|
||||
dvbsub_parse_page_segment(dvb_ctx, p, segment_length);
|
||||
dvbsub_parse_page_segment(ctx, p, segment_length);
|
||||
got_segment |= 1;
|
||||
break;
|
||||
case DVBSUB_REGION_SEGMENT:
|
||||
dvbsub_parse_region_segment(dvb_ctx, p, segment_length);
|
||||
dvbsub_parse_region_segment(ctx, p, segment_length);
|
||||
got_segment |= 2;
|
||||
break;
|
||||
case DVBSUB_CLUT_SEGMENT:
|
||||
ret = dvbsub_parse_clut_segment(dvb_ctx, p, segment_length);
|
||||
ret = dvbsub_parse_clut_segment(ctx, p, segment_length);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
got_segment |= 4;
|
||||
break;
|
||||
case DVBSUB_OBJECT_SEGMENT:
|
||||
dvbsub_parse_object_segment(dvb_ctx, p, segment_length);
|
||||
dvbsub_parse_object_segment(ctx, p, segment_length);
|
||||
got_segment |= 8;
|
||||
break;
|
||||
case DVBSUB_DISPLAYDEFINITION_SEGMENT:
|
||||
dvbsub_parse_display_definition_segment(dvb_ctx, p,
|
||||
dvbsub_parse_display_definition_segment(ctx, p,
|
||||
segment_length);
|
||||
break;
|
||||
case DVBSUB_DISPLAY_SEGMENT:
|
||||
write_dvb_sub(dvb_ctx,sub);
|
||||
write_dvb_sub(dec_ctx, sub);
|
||||
got_segment |= 16;
|
||||
break;
|
||||
default:
|
||||
@@ -1618,7 +1637,7 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
|
||||
// segments then we need no further data.
|
||||
if (got_segment == 15)
|
||||
{
|
||||
write_dvb_sub(dvb_ctx,sub);
|
||||
write_dvb_sub(dec_ctx, sub);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ struct dvb_config
|
||||
*/
|
||||
void* dvbsub_init_decoder(struct dvb_config* cfg);
|
||||
|
||||
int dvbsub_close_decoder(void *dvb_ctx);
|
||||
int dvbsub_close_decoder(void **dvb_ctx);
|
||||
|
||||
/**
|
||||
* @param dvb_ctx PreInitialized DVB context using DVB
|
||||
@@ -55,7 +55,7 @@ int dvbsub_close_decoder(void *dvb_ctx);
|
||||
*
|
||||
* @return -1 on error
|
||||
*/
|
||||
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub);
|
||||
int dvbsub_decode(struct lib_cc_decode *dec_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub);
|
||||
|
||||
/**
|
||||
* @func parse_dvb_description
|
||||
|
||||
@@ -1,43 +1,28 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "activity.h"
|
||||
|
||||
// Functions to parse a mpeg-2 data stream, see ISO/IEC 13818-2 6.2
|
||||
|
||||
static int no_bitstream_error = 0;
|
||||
static int saw_seqgoppic = 0;
|
||||
static int in_pic_data = 0;
|
||||
|
||||
static unsigned current_progressive_sequence = 2;
|
||||
static unsigned current_pulldownfields = 32768;
|
||||
|
||||
static int temporal_reference = 0;
|
||||
static enum ccx_frame_type picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
static unsigned picture_structure = 0;
|
||||
unsigned top_field_first = 0; // Needs to be global
|
||||
static unsigned repeat_first_field = 0;
|
||||
static unsigned progressive_frame = 0;
|
||||
static unsigned pulldownfields = 0;
|
||||
|
||||
|
||||
static uint8_t search_start_code(struct bitstream *esstream);
|
||||
static uint8_t next_start_code(struct bitstream *esstream);
|
||||
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream);
|
||||
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream);
|
||||
static int sequence_ext(struct bitstream *esstream);
|
||||
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int pic_header(struct bitstream *esstream);
|
||||
static int pic_coding_ext(struct bitstream *esstream);
|
||||
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int es_video_sequence(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int sequence_header(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int read_gop_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int gop_header(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_pic_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int pic_header(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int read_eau_info(struct lib_cc_decode* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int extension_and_user_data(struct lib_cc_decode *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int read_pic_data(struct bitstream *esstream);
|
||||
|
||||
|
||||
#define debug( ... ) ccx_common_logging.debug_ftn( CCX_DMT_VERBOSE, __VA_ARGS__)
|
||||
/* Process a mpeg-2 data stream with "lenght" bytes in buffer "data".
|
||||
* The number of processed bytes is returned.
|
||||
* Defined in ISO/IEC 13818-2 6.2 */
|
||||
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG length, struct cc_subtitle *sub)
|
||||
size_t process_m2v (struct lib_cc_decode *ctx, unsigned char *data, size_t length, struct cc_subtitle *sub)
|
||||
{
|
||||
if (length<8) // Need to look ahead 8 bytes
|
||||
return length;
|
||||
@@ -71,7 +56,7 @@ static uint8_t search_start_code(struct bitstream *esstream)
|
||||
// Keep a negative esstream->bitsleft, but correct it.
|
||||
if (esstream->bitsleft <= 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "search_start_code: bitsleft <= 0\n");
|
||||
debug("search_start_code: bitsleft <= 0\n");
|
||||
esstream->bitsleft -= 8*4;
|
||||
return 0xB4;
|
||||
}
|
||||
@@ -110,12 +95,12 @@ static uint8_t search_start_code(struct bitstream *esstream)
|
||||
esstream->pos = tstr;
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "search_start_code: bitsleft <= 0\n");
|
||||
debug("search_start_code: bitsleft <= 0\n");
|
||||
return 0xB4;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "search_start_code: Found %02X\n", tstr[3]);
|
||||
debug("search_start_code: Found %02X\n", tstr[3]);
|
||||
return tstr[3];
|
||||
}
|
||||
}
|
||||
@@ -142,7 +127,7 @@ static uint8_t next_start_code(struct bitstream *esstream)
|
||||
// Only start looking if there is enough data. Adjust bitsleft.
|
||||
if (esstream->bitsleft < 4*8)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "next_start_code: bitsleft %lld < 32\n", esstream->bitsleft);
|
||||
debug("next_start_code: bitsleft %lld < 32\n", esstream->bitsleft);
|
||||
esstream->bitsleft -= 8*4;
|
||||
return 0xB4;
|
||||
}
|
||||
@@ -154,7 +139,7 @@ static uint8_t next_start_code(struct bitstream *esstream)
|
||||
tmp = read_u8(esstream);
|
||||
if (tmp)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "next_start_code: Non zero stuffing\n");
|
||||
debug("next_start_code: Non zero stuffing\n");
|
||||
esstream->error = 1;
|
||||
return 0xB4;
|
||||
}
|
||||
@@ -163,16 +148,16 @@ static uint8_t next_start_code(struct bitstream *esstream)
|
||||
if (esstream->bitsleft < 8)
|
||||
{
|
||||
esstream->bitsleft -= 8;
|
||||
dbg_print(CCX_DMT_VERBOSE, "next_start_code: bitsleft <= 0\n");
|
||||
debug("next_start_code: bitsleft <= 0\n");
|
||||
return 0xB4;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "next_start_code: Found %02X\n", *(esstream->pos+3));
|
||||
debug("next_start_code: Found %02X\n", *(esstream->pos+3));
|
||||
|
||||
if ( *(esstream->pos+3) == 0xB4 )
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "B4: assume bitstream syntax error!\n");
|
||||
debug("B4: assume bitstream syntax error!\n");
|
||||
esstream->error = 1;
|
||||
}
|
||||
|
||||
@@ -185,19 +170,19 @@ static uint8_t next_start_code(struct bitstream *esstream)
|
||||
// Otherwise. estream->pos shall point to the position where
|
||||
// the next call will continue, i.e. the possible begin of an
|
||||
// unfinished video sequence or after the finished sequence.
|
||||
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int es_video_sequence(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
// Avoid "Skip forward" message on first call and later only
|
||||
// once per search.
|
||||
static int noskipmessage = 1;
|
||||
uint8_t startcode;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "es_video_sequence()\n");
|
||||
debug("es_video_sequence()\n");
|
||||
|
||||
esstream->error = 0;
|
||||
|
||||
// Analyze sequence header ...
|
||||
if (!no_bitstream_error)
|
||||
if (!ctx->no_bitstream_error)
|
||||
{
|
||||
// We might start here because of a syntax error. Discard
|
||||
// all data until a new sequence_header_code or group_start_code
|
||||
@@ -225,27 +210,27 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
|
||||
skip_bits(esstream, 4*8);
|
||||
}
|
||||
|
||||
no_bitstream_error = 1;
|
||||
saw_seqgoppic = 0;
|
||||
in_pic_data = 0;
|
||||
ctx->no_bitstream_error = 1;
|
||||
ctx->saw_seqgoppic = 0;
|
||||
ctx->in_pic_data = 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
startcode = next_start_code(esstream);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nM2V - next start code %02X %d\n", startcode, in_pic_data);
|
||||
debug("\nM2V - next start code %02X %d\n", startcode, ctx->in_pic_data);
|
||||
|
||||
// Syntax check - also returns on bitsleft < 0
|
||||
if (startcode == 0xB4)
|
||||
{
|
||||
if (esstream->error)
|
||||
{
|
||||
no_bitstream_error = 0;
|
||||
dbg_print(CCX_DMT_VERBOSE, "es_video_sequence: syntax problem.\n");
|
||||
ctx->no_bitstream_error = 0;
|
||||
debug("es_video_sequence: syntax problem.\n");
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "es_video_sequence: return on B4 startcode.\n");
|
||||
debug("es_video_sequence: return on B4 startcode.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -254,72 +239,72 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
|
||||
if (startcode == 0xB7)
|
||||
{
|
||||
skip_u32(esstream); // Advance bitstream
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!in_pic_data && startcode == 0xB3)
|
||||
if (!ctx->in_pic_data && startcode == 0xB3)
|
||||
{
|
||||
if (!read_seq_info(ctx, esstream))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
return 0;
|
||||
}
|
||||
saw_seqgoppic = 1;
|
||||
ctx->saw_seqgoppic = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_pic_data && startcode == 0xB8)
|
||||
if (!ctx->in_pic_data && startcode == 0xB8)
|
||||
{
|
||||
if (!read_gop_info(ctx, esstream,sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
return 0;
|
||||
}
|
||||
saw_seqgoppic = 2;
|
||||
ctx->saw_seqgoppic = 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_pic_data && startcode == 0x00)
|
||||
if (!ctx->in_pic_data && startcode == 0x00)
|
||||
{
|
||||
if (!read_pic_info(ctx, esstream, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
return 0;
|
||||
}
|
||||
saw_seqgoppic = 3;
|
||||
in_pic_data = 1;
|
||||
ctx->saw_seqgoppic = 3;
|
||||
ctx->in_pic_data = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only looks for extension and user data if we saw sequence, gop
|
||||
// or picture info before.
|
||||
// This check needs to be before the "in_pic_data" part.
|
||||
if ( saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
|
||||
// This check needs to be before the "ctx->in_pic_data" part.
|
||||
if ( ctx->saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
|
||||
{
|
||||
if (!read_eau_info(ctx, esstream, saw_seqgoppic-1, sub))
|
||||
if (!read_eau_info(ctx, esstream, ctx->saw_seqgoppic-1, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
return 0;
|
||||
}
|
||||
saw_seqgoppic = 0;
|
||||
ctx->saw_seqgoppic = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_pic_data) // See comment in read_pic_data()
|
||||
if (ctx->in_pic_data) // See comment in read_pic_data()
|
||||
{
|
||||
if (!read_pic_data(esstream))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
return 0;
|
||||
}
|
||||
saw_seqgoppic = 0;
|
||||
in_pic_data = 0;
|
||||
ctx->saw_seqgoppic = 0;
|
||||
ctx->in_pic_data = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -332,7 +317,7 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
|
||||
{
|
||||
mprint("\nUnexpected startcode: %02X\n", startcode);
|
||||
}
|
||||
no_bitstream_error = 0;
|
||||
ctx->no_bitstream_error = 0;
|
||||
return 0;
|
||||
} while(1);
|
||||
|
||||
@@ -344,9 +329,9 @@ static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Sequence Info\n");
|
||||
debug("Read Sequence Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
|
||||
@@ -358,7 +343,7 @@ static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
unsigned char *video_seq_start = esstream->pos;
|
||||
|
||||
sequence_header(ctx, esstream);
|
||||
sequence_ext(esstream);
|
||||
sequence_ext(ctx, esstream);
|
||||
// FIXME: if sequence extension is missing this is not MPEG-2,
|
||||
// or broken. Set bitstream error.
|
||||
//extension_and_user_data(esstream);
|
||||
@@ -372,7 +357,7 @@ static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Sequence Info - processed\n\n");
|
||||
debug("Read Sequence Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -381,9 +366,9 @@ static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
static int sequence_header(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Sequence header\n");
|
||||
debug("Sequence header\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
@@ -397,10 +382,12 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
unsigned aspect_ratio = (unsigned) read_bits(esstream,4);
|
||||
unsigned frame_rate = (unsigned) read_bits(esstream,4);
|
||||
|
||||
#if 0
|
||||
ctx->freport.width = hor_size;
|
||||
ctx->freport.height = vert_size;
|
||||
ctx->freport.aspect_ratio = aspect_ratio;
|
||||
ctx->freport.frame_rate = frame_rate;
|
||||
#endif
|
||||
|
||||
// Discard some information
|
||||
read_bits(esstream, 18+1+10+1);
|
||||
@@ -416,10 +403,10 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
return 0;
|
||||
|
||||
// If we got the whole sequence, process
|
||||
if (hor_size!=current_hor_size ||
|
||||
vert_size!=current_vert_size ||
|
||||
aspect_ratio!=current_aspect_ratio ||
|
||||
frame_rate!=current_frame_rate)
|
||||
if (hor_size!= ctx->current_hor_size ||
|
||||
vert_size!= ctx->current_vert_size ||
|
||||
aspect_ratio!=ctx->current_aspect_ratio ||
|
||||
frame_rate!= ctx->current_frame_rate)
|
||||
{
|
||||
// If horizontal/vertical size, framerate and/or aspect
|
||||
// ratio are ilegal, we discard the
|
||||
@@ -432,12 +419,6 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
aspect_ratio>0 && aspect_ratio<5)
|
||||
{
|
||||
mprint ("\n\nNew video information found");
|
||||
if (pts_set==2)
|
||||
{
|
||||
unsigned cur_sec = (unsigned) ((current_pts - min_pts)
|
||||
/ MPEG_CLOCK_FREQ);
|
||||
mprint (" at %02u:%02u",cur_sec/60, cur_sec % 60);
|
||||
}
|
||||
mprint ("\n");
|
||||
mprint ("[%u * %u] [AR: %s] [FR: %s]",
|
||||
hor_size,vert_size,
|
||||
@@ -445,21 +426,21 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
framerates_types[frame_rate]);
|
||||
// No newline, force the output of progressive info in picture
|
||||
// info part.
|
||||
current_progressive_sequence = 2;
|
||||
ctx->current_progressive_sequence = 2;
|
||||
|
||||
current_hor_size=hor_size;
|
||||
current_vert_size=vert_size;
|
||||
current_aspect_ratio=aspect_ratio;
|
||||
current_frame_rate=frame_rate;
|
||||
current_fps = framerates_values[current_frame_rate];
|
||||
ctx->current_hor_size = hor_size;
|
||||
ctx->current_vert_size = vert_size;
|
||||
ctx->current_aspect_ratio = aspect_ratio;
|
||||
ctx->current_frame_rate=frame_rate;
|
||||
current_fps = framerates_values[ctx->current_frame_rate];
|
||||
activity_video_info (hor_size,vert_size,
|
||||
aspect_ratio_types[aspect_ratio],
|
||||
framerates_types[frame_rate]);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nInvalid sequence header:\n");
|
||||
dbg_print(CCX_DMT_VERBOSE, "V: %u H: %u FR: %u AS: %u\n",
|
||||
debug("\nInvalid sequence header:\n");
|
||||
debug("V: %u H: %u FR: %u AS: %u\n",
|
||||
vert_size, hor_size, frame_rate, aspect_ratio);
|
||||
esstream->error = 1;
|
||||
return 0;
|
||||
@@ -474,9 +455,9 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int sequence_ext(struct bitstream *esstream)
|
||||
static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Sequence extension\n");
|
||||
debug("Sequence extension\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
@@ -484,7 +465,7 @@ static int sequence_ext(struct bitstream *esstream)
|
||||
// Syntax check
|
||||
if (next_start_code(esstream) != 0xB5)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "sequence_ext: syntax problem.\n");
|
||||
debug("sequence_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -498,7 +479,7 @@ static int sequence_ext(struct bitstream *esstream)
|
||||
esstream->error = 1;
|
||||
|
||||
if (esstream->error)
|
||||
dbg_print(CCX_DMT_VERBOSE, "sequence_ext: syntax problem.\n");
|
||||
debug("sequence_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -506,9 +487,9 @@ static int sequence_ext(struct bitstream *esstream)
|
||||
skip_bits(esstream, 8);
|
||||
unsigned progressive_sequence = (unsigned) read_bits(esstream,1);
|
||||
|
||||
if (progressive_sequence!=current_progressive_sequence)
|
||||
if (progressive_sequence!=ctx->current_progressive_sequence)
|
||||
{
|
||||
current_progressive_sequence = progressive_sequence;
|
||||
ctx->current_progressive_sequence = progressive_sequence;
|
||||
mprint(" [progressive: %s]\n\n",
|
||||
(progressive_sequence ? "yes" : "no"));
|
||||
}
|
||||
@@ -527,9 +508,9 @@ static int sequence_ext(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int read_gop_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info\n");
|
||||
debug("Read GOP Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
|
||||
@@ -552,7 +533,7 @@ static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info - processed\n\n");
|
||||
debug("Read GOP Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -561,9 +542,9 @@ static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int gop_header(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "GOP header\n");
|
||||
debug("GOP header\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
@@ -592,21 +573,21 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
|
||||
// do the padding.
|
||||
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (has_ccdata_buffered)
|
||||
if (ctx->has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(ctx, sub);
|
||||
}
|
||||
|
||||
// Last GOPs pulldown frames
|
||||
if ((current_pulldownfields>0) != (pulldownfields>0))
|
||||
if ((ctx->current_pulldownfields>0) != (ctx->pulldownfields>0))
|
||||
{
|
||||
current_pulldownfields = pulldownfields;
|
||||
dbg_print(CCX_DMT_VERBOSE, "Pulldown: %s", (pulldownfields ? "on" : "off"));
|
||||
if (pulldownfields)
|
||||
dbg_print(CCX_DMT_VERBOSE, " - %u fields in last GOP", pulldownfields);
|
||||
dbg_print(CCX_DMT_VERBOSE, "\n");
|
||||
ctx->current_pulldownfields = ctx->pulldownfields;
|
||||
debug("Pulldown: %s", (ctx->pulldownfields ? "on" : "off"));
|
||||
if (ctx->pulldownfields)
|
||||
debug(" - %u fields in last GOP", ctx->pulldownfields);
|
||||
debug("\n");
|
||||
}
|
||||
pulldownfields = 0;
|
||||
ctx->pulldownfields = 0;
|
||||
|
||||
// Report synchronization jumps between GOPs. Warn if there
|
||||
// are 20% or more deviation.
|
||||
@@ -637,22 +618,22 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
|
||||
// need the length of all frames.
|
||||
if ( total_frames_count == 0 )
|
||||
{ // If this is the first frame there cannot be an offset
|
||||
fts_fc_offset = 0;
|
||||
ctx->timing->fts_fc_offset = 0;
|
||||
// first_gop_time.ms stays unchanged
|
||||
}
|
||||
else
|
||||
{
|
||||
fts_fc_offset = (LLONG) ((total_frames_count+1)
|
||||
ctx->timing->fts_fc_offset = (LLONG) ((total_frames_count+1)
|
||||
*1000.0/current_fps);
|
||||
// Compensate for those written before
|
||||
first_gop_time.ms -= fts_fc_offset;
|
||||
first_gop_time.ms -= ctx->timing->fts_fc_offset;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_TIME, "\nFirst GOP time: %02u:%02u:%02u:%03u %+lldms\n",
|
||||
gtc.time_code_hours,
|
||||
gtc.time_code_minutes, gtc.time_code_seconds,
|
||||
(unsigned) (1000.0*gtc.time_code_pictures/current_fps),
|
||||
fts_fc_offset);
|
||||
ctx->timing->fts_fc_offset);
|
||||
}
|
||||
|
||||
gop_time = gtc;
|
||||
@@ -664,13 +645,11 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
|
||||
// If we use GOP timing, reconstruct the PTS from the GOP
|
||||
if (ccx_options.use_gop_as_pts==1)
|
||||
{
|
||||
current_pts = gtc.ms*(MPEG_CLOCK_FREQ/1000);
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
current_tref = 0;
|
||||
set_current_pts(ctx->timing, gtc.ms*(MPEG_CLOCK_FREQ/1000));
|
||||
ctx->timing->current_tref = 0;
|
||||
frames_since_ref_time = 0;
|
||||
set_fts();
|
||||
fts_at_gop_start = get_fts_max();
|
||||
set_fts(ctx->timing);
|
||||
fts_at_gop_start = get_fts_max(ctx->timing);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -679,14 +658,14 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
|
||||
// next GOP.
|
||||
// This effect will also lead to captions being one GOP early
|
||||
// for DVD captions.
|
||||
fts_at_gop_start = get_fts_max() + (LLONG) (1000.0/current_fps);
|
||||
fts_at_gop_start = get_fts_max(ctx->timing) + (LLONG) (1000.0/current_fps);
|
||||
}
|
||||
|
||||
if (ccx_options.debug_mask & CCX_DMT_TIME)
|
||||
{
|
||||
dbg_print(CCX_DMT_TIME, "\nNew GOP:\n");
|
||||
dbg_print(CCX_DMT_TIME, "\nDrop frame flag: %u:\n", drop_frame_flag);
|
||||
print_debug_timing();
|
||||
print_debug_timing(ctx->timing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,9 +677,9 @@ static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struc
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int read_pic_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info\n");
|
||||
debug("Read PIC Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100)
|
||||
@@ -711,8 +690,8 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
// after getting more.
|
||||
unsigned char *pic_info_start = esstream->pos;
|
||||
|
||||
pic_header(esstream);
|
||||
pic_coding_ext(esstream);
|
||||
pic_header(ctx, esstream);
|
||||
pic_coding_ext(ctx, esstream);
|
||||
|
||||
if (esstream->error)
|
||||
return 0;
|
||||
@@ -723,45 +702,36 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Analyse/use the picture information
|
||||
static int maxtref; // Use to remember the temporal reference number
|
||||
|
||||
// A new anchor frame - flush buffered caption data. Might be flushed
|
||||
// in GOP header already.
|
||||
if (picture_coding_type==CCX_FRAME_TYPE_I_FRAME || picture_coding_type==CCX_FRAME_TYPE_P_FRAME)
|
||||
if (ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME || ctx->picture_coding_type==CCX_FRAME_TYPE_P_FRAME)
|
||||
{
|
||||
if (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
|
||||
(temporal_reference != current_tref))
|
||||
if (((ctx->picture_structure != 0x1) && (ctx->picture_structure != 0x2)) ||
|
||||
(ctx->temporal_reference != ctx->timing->current_tref))
|
||||
{
|
||||
// NOTE: process_hdcc() needs to be called before set_fts() as it
|
||||
// uses fts_now to re-create the timeline !!!!!
|
||||
if (has_ccdata_buffered)
|
||||
if (ctx->has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(ctx, sub);
|
||||
}
|
||||
anchor_hdcc(temporal_reference);
|
||||
anchor_hdcc(ctx, ctx->temporal_reference);
|
||||
}
|
||||
}
|
||||
|
||||
current_tref = temporal_reference;
|
||||
current_picture_coding_type = picture_coding_type;
|
||||
ctx->timing->current_tref = ctx->temporal_reference;
|
||||
ctx->timing->current_picture_coding_type = ctx->picture_coding_type;
|
||||
|
||||
// We mostly use PTS, but when the GOP mode is enabled do not set
|
||||
// the FTS time here.
|
||||
if (ccx_options.use_gop_as_pts!=1)
|
||||
{
|
||||
set_fts(); // Initialize fts
|
||||
set_fts(ctx->timing); // Initialize fts
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u) - tref: %2d - %s since tref0/GOP: %2u/%2u",
|
||||
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts), temporal_reference,
|
||||
pict_types[picture_coding_type],
|
||||
(unsigned) (frames_since_ref_time),
|
||||
(unsigned) (ctx->frames_since_last_gop));
|
||||
dbg_print(CCX_DMT_VIDES, " t:%d r:%d p:%d", top_field_first,
|
||||
repeat_first_field, progressive_frame);
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
dbg_print(CCX_DMT_VIDES, " t:%d r:%d p:%d", ctx->top_field_first,
|
||||
ctx->repeat_first_field, ctx->progressive_frame);
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts(ctx->timing, ctx->current_field)));
|
||||
|
||||
// Set min_pts/sync_pts according to the current time stamp.
|
||||
// Use fts_at_gop_start as reference when a GOP header was seen
|
||||
@@ -770,10 +740,10 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
// header. Use the current FTS values as reference.
|
||||
// Note: If a GOP header was present the reference time is from
|
||||
// the beginning of the GOP, otherwise it is now.
|
||||
if(temporal_reference == 0)
|
||||
if(ctx->temporal_reference == 0)
|
||||
{
|
||||
ctx->last_gop_length = maxtref + 1;
|
||||
maxtref = temporal_reference;
|
||||
ctx->last_gop_length = ctx->maxtref + 1;
|
||||
ctx->maxtref = ctx->temporal_reference;
|
||||
|
||||
// frames_since_ref_time is used in set_fts()
|
||||
|
||||
@@ -786,20 +756,20 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
else
|
||||
{
|
||||
// No GOP header, use the current values
|
||||
fts_at_gop_start=get_fts();
|
||||
fts_at_gop_start = get_fts(ctx->timing, ctx->current_field);
|
||||
frames_since_ref_time = 0;
|
||||
}
|
||||
|
||||
if (ccx_options.debug_mask & CCX_DMT_TIME)
|
||||
{
|
||||
dbg_print(CCX_DMT_TIME, "\nNew temporal reference:\n");
|
||||
print_debug_timing();
|
||||
print_debug_timing(ctx->timing);
|
||||
}
|
||||
|
||||
ctx->saw_gop_header = 0; // Reset the value
|
||||
}
|
||||
|
||||
if ( !ctx->saw_gop_header && picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
|
||||
if ( !ctx->saw_gop_header && ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
|
||||
{
|
||||
// A new GOP beginns with an I-frame. Lets hope there are
|
||||
// never more than one per GOP
|
||||
@@ -807,20 +777,20 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
}
|
||||
|
||||
// Set maxtref
|
||||
if( temporal_reference > maxtref ) {
|
||||
maxtref = temporal_reference;
|
||||
if (maxtref+1 > ctx->max_gop_length)
|
||||
ctx->max_gop_length = maxtref+1;
|
||||
if( ctx->temporal_reference > ctx->maxtref ) {
|
||||
ctx->maxtref = ctx->temporal_reference;
|
||||
if (ctx->maxtref + 1 > ctx->max_gop_length)
|
||||
ctx->max_gop_length = ctx->maxtref + 1;
|
||||
}
|
||||
|
||||
unsigned extraframe = 0;
|
||||
if (repeat_first_field)
|
||||
if (ctx->repeat_first_field)
|
||||
{
|
||||
pulldownfields++;
|
||||
ctx->pulldownfields++;
|
||||
ctx->total_pulldownfields++;
|
||||
if ( current_progressive_sequence || !(ctx->total_pulldownfields%2) )
|
||||
if ( ctx->current_progressive_sequence || !(ctx->total_pulldownfields%2) )
|
||||
extraframe = 1;
|
||||
if ( current_progressive_sequence && top_field_first )
|
||||
if ( ctx->current_progressive_sequence && ctx->top_field_first )
|
||||
extraframe = 2;
|
||||
dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
|
||||
ctx->total_pulldownfields, extraframe);
|
||||
@@ -831,7 +801,7 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
ctx->frames_since_last_gop += 1+extraframe;
|
||||
frames_since_ref_time += 1+extraframe;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info - processed\n\n");
|
||||
debug("Read PIC Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -840,9 +810,9 @@ static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, st
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int pic_header(struct bitstream *esstream)
|
||||
static int pic_header(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "PIC header\n");
|
||||
debug("PIC header\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
@@ -851,16 +821,16 @@ static int pic_header(struct bitstream *esstream)
|
||||
if (read_u32(esstream) != 0x00010000) // LSB first (0x00000100)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
|
||||
|
||||
temporal_reference = (int) read_bits(esstream,10);
|
||||
picture_coding_type = (enum ccx_frame_type) read_bits(esstream,3);
|
||||
ctx->temporal_reference = (int) read_bits(esstream,10);
|
||||
ctx->picture_coding_type = (enum ccx_frame_type) read_bits(esstream,3);
|
||||
|
||||
// Discard vbv_delay
|
||||
skip_bits(esstream, 16);
|
||||
|
||||
// Discard some information
|
||||
if (picture_coding_type == 2 || picture_coding_type == 3)
|
||||
if (ctx->picture_coding_type == 2 || ctx->picture_coding_type == 3)
|
||||
skip_bits(esstream, 4);
|
||||
if (picture_coding_type == 3)
|
||||
if (ctx->picture_coding_type == 3)
|
||||
skip_bits(esstream, 4);
|
||||
|
||||
// extra_information
|
||||
@@ -872,15 +842,15 @@ static int pic_header(struct bitstream *esstream)
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
if ( !(picture_coding_type==CCX_FRAME_TYPE_I_FRAME
|
||||
|| picture_coding_type==CCX_FRAME_TYPE_P_FRAME
|
||||
|| picture_coding_type==CCX_FRAME_TYPE_B_FRAME))
|
||||
if ( !(ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME
|
||||
|| ctx->picture_coding_type==CCX_FRAME_TYPE_P_FRAME
|
||||
|| ctx->picture_coding_type==CCX_FRAME_TYPE_B_FRAME))
|
||||
{
|
||||
if (esstream->bitsleft >= 0) // When bits left, this is wrong
|
||||
esstream->error = 1;
|
||||
|
||||
if (esstream->error)
|
||||
dbg_print(CCX_DMT_VERBOSE, "pic_header: syntax problem.\n");
|
||||
debug("pic_header: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -891,9 +861,9 @@ static int pic_header(struct bitstream *esstream)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int pic_coding_ext(struct bitstream *esstream)
|
||||
static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Picture coding extension %lld\n", esstream->bitsleft);
|
||||
debug("Picture coding extension %lld\n", esstream->bitsleft);
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
@@ -901,7 +871,7 @@ static int pic_coding_ext(struct bitstream *esstream)
|
||||
// Syntax check
|
||||
if (next_start_code(esstream) != 0xB5)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "pic_coding_ext: syntax problem.\n");
|
||||
debug("pic_coding_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -915,18 +885,18 @@ static int pic_coding_ext(struct bitstream *esstream)
|
||||
esstream->error = 1;
|
||||
|
||||
if (esstream->error)
|
||||
dbg_print(CCX_DMT_VERBOSE, "pic_coding_ext: syntax problem.\n");
|
||||
debug("pic_coding_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Discard some information
|
||||
skip_bits(esstream, 4*4+2);
|
||||
picture_structure = (unsigned int) read_bits(esstream, 2);
|
||||
top_field_first = (unsigned int) read_bits(esstream, 1);
|
||||
ctx->picture_structure = (unsigned int) read_bits(esstream, 2);
|
||||
ctx->top_field_first = (unsigned int) read_bits(esstream, 1);
|
||||
skip_bits(esstream, 5*1);
|
||||
repeat_first_field = (unsigned int) read_bits(esstream, 1);
|
||||
ctx->repeat_first_field = (unsigned int) read_bits(esstream, 1);
|
||||
skip_bits(esstream, 1); // chroma
|
||||
progressive_frame = (unsigned int) read_bits(esstream, 1);
|
||||
ctx->progressive_frame = (unsigned int) read_bits(esstream, 1);
|
||||
unsigned composite_display = (unsigned int) read_bits(esstream,1);
|
||||
if (composite_display)
|
||||
skip_bits(esstream, 1+3+1+7+8);
|
||||
@@ -934,7 +904,7 @@ static int pic_coding_ext(struct bitstream *esstream)
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Picture coding extension - processed\n");
|
||||
debug("Picture coding extension - processed\n");
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
@@ -945,9 +915,9 @@ static int pic_coding_ext(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
static int read_eau_info(struct lib_cc_decode* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info\n");
|
||||
debug("Read Extension and User Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
unsigned char *tst = next_bytes(esstream, 4);
|
||||
@@ -962,14 +932,14 @@ static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, in
|
||||
if( !extension_and_user_data(ctx, esstream, udtype, sub) )
|
||||
{
|
||||
if (esstream->error)
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nWarning: Retry while reading Extension and User Data!\n");
|
||||
debug("\nWarning: Retry while reading Extension and User Data!\n");
|
||||
else
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nBitstream problem while reading Extension and User Data!\n");
|
||||
debug("\nBitstream problem while reading Extension and User Data!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info - processed\n\n");
|
||||
debug("Read Extension and User Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -978,9 +948,9 @@ static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, in
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
static int extension_and_user_data(struct lib_cc_decode *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data(%d)\n", udtype);
|
||||
debug("Extension and user data(%d)\n", udtype);
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
@@ -1013,13 +983,13 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
|
||||
|
||||
if (esstream->error)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - syntax problem\n");
|
||||
debug("Extension and user data - syntax problem\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - inclomplete\n");
|
||||
debug("Extension and user data - inclomplete\n");
|
||||
// Restore to where we need to continue
|
||||
init_bitstream(esstream, eau_start, esstream->end);
|
||||
esstream->bitsleft = -1; // Redundant
|
||||
@@ -1034,7 +1004,7 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Skip %d bytes extension data.\n",
|
||||
debug("Skip %d bytes extension data.\n",
|
||||
esstream->pos - dstart);
|
||||
}
|
||||
// If we get here esstream points to the end of a block
|
||||
@@ -1047,19 +1017,19 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
|
||||
|
||||
if (esstream->error)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - syntax problem\n");
|
||||
debug("Extension and user data - syntax problem\n");
|
||||
return 0;
|
||||
}
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - inclomplete\n");
|
||||
debug("Extension and user data - inclomplete\n");
|
||||
// Restore to where we need to continue
|
||||
init_bitstream(esstream, eau_start, esstream->end);
|
||||
esstream->bitsleft = -1; // Redundant
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data - processed\n");
|
||||
debug("Extension and user data - processed\n");
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
@@ -1072,7 +1042,7 @@ static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *es
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_pic_data(struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read PIC Data\n");
|
||||
debug("Read PIC Data\n");
|
||||
|
||||
uint8_t startcode = next_start_code(esstream);
|
||||
|
||||
@@ -1083,7 +1053,7 @@ static int read_pic_data(struct bitstream *esstream)
|
||||
// We only get here after seeing that start code
|
||||
if (startcode < 0x01 || startcode > 0xAF)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Pic Data - processed0\n");
|
||||
debug("Read Pic Data - processed0\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1103,9 +1073,9 @@ static int read_pic_data(struct bitstream *esstream)
|
||||
init_bitstream(esstream, slice_start, esstream->end);
|
||||
|
||||
if ( esstream->error )
|
||||
dbg_print(CCX_DMT_VERBOSE, "read_pic_data: syntax problem.\n");
|
||||
debug("read_pic_data: syntax problem.\n");
|
||||
else
|
||||
dbg_print(CCX_DMT_VERBOSE, "read_pic_data: reached end of bitstream.\n");
|
||||
debug("read_pic_data: reached end of bitstream.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1125,7 +1095,7 @@ static int read_pic_data(struct bitstream *esstream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Pic Data - processed\n");
|
||||
debug("Read Pic Data - processed\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,8 @@
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if ustream->error
|
||||
// is FALSE, parsing can set ustream->error to TRUE.
|
||||
int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
int user_data(struct lib_cc_decode *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype);
|
||||
|
||||
// Shall not happen
|
||||
@@ -25,7 +23,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
}
|
||||
|
||||
// Do something
|
||||
ctx->stat_numuserheaders++;
|
||||
//ctx->stat_numuserheaders++;
|
||||
//header+=4;
|
||||
|
||||
unsigned char *ud_header = next_bytes(ustream, 4);
|
||||
@@ -40,7 +38,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
|
||||
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
|
||||
{
|
||||
ctx->stat_dvdccheaders++;
|
||||
// ctx->stat_dvdccheaders++;
|
||||
|
||||
// Probably unneeded, but keep looking for extra caption blocks
|
||||
int maybeextracb = 1;
|
||||
@@ -66,8 +64,8 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
// current time to one frame after the maximum time of the
|
||||
// last GOP. Only usefull when there are frames before
|
||||
// the GOP.
|
||||
if (fts_max > 0)
|
||||
fts_now = fts_max + (LLONG) (1000.0/current_fps);
|
||||
if (ctx->timing->fts_max > 0)
|
||||
ctx->timing->fts_now = ctx->timing->fts_max + (LLONG) (1000.0/current_fps);
|
||||
|
||||
int rcbcount = 0;
|
||||
for (int i=0; i<capcount; i++)
|
||||
@@ -94,7 +92,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(dec_ctx, data, sub);
|
||||
do_cb(ctx, data, sub);
|
||||
rcbcount++;
|
||||
}
|
||||
else
|
||||
@@ -125,7 +123,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(dec_ctx, data, sub);
|
||||
do_cb(ctx, data, sub);
|
||||
ecbcount++;
|
||||
}
|
||||
else
|
||||
@@ -146,7 +144,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
{
|
||||
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
|
||||
|
||||
ctx->stat_scte20ccheaders++;
|
||||
// ctx->stat_scte20ccheaders++;
|
||||
read_bytes(ustream, 2); // "03 01"
|
||||
|
||||
unsigned cc_count = (unsigned int) read_bits(ustream,5);
|
||||
@@ -186,7 +184,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
field_number = (field_number - 1) & 0x01;
|
||||
// top_field_first also affects to which field the caption
|
||||
// belongs.
|
||||
if(!top_field_first)
|
||||
if(!ctx->top_field_first)
|
||||
field_number ^= 0x01;
|
||||
cc_data[j*3]=0x04|(field_number);
|
||||
cc_data[j*3+1]=reverse8(cc_data1);
|
||||
@@ -194,7 +192,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
}
|
||||
}
|
||||
cc_data[cc_count*3]=0xFF;
|
||||
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, cc_data, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
|
||||
}
|
||||
@@ -207,26 +205,28 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
&& ud_header[1] == 0x02 )
|
||||
{
|
||||
unsigned char data[3];
|
||||
#if 0
|
||||
if (ud_header[0]==0xbb)
|
||||
ctx->stat_replay4000headers++;
|
||||
else
|
||||
ctx->stat_replay5000headers++;
|
||||
#endif
|
||||
|
||||
read_bytes(ustream, 2); // "BB 02" or "99 02"
|
||||
data[0]=0x05; // Field 2
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
do_cb(ctx, data, sub);
|
||||
read_bytes(ustream, 2); // Skip "CC 02" for R4000 or "AA 02" for R5000
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
do_cb(ctx, data, sub);
|
||||
}
|
||||
// HDTV - see A/53 Part 4 (Video)
|
||||
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
|
||||
{
|
||||
ctx->stat_hdtv++;
|
||||
// ctx->stat_hdtv++;
|
||||
|
||||
read_bytes(ustream, 4); // "47 41 39 34"
|
||||
|
||||
@@ -266,7 +266,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
// Please note we store the current value of the global
|
||||
// fts_now variable (and not get_fts()) as we are going to
|
||||
// re-create the timeline in process_hdcc() (Slightly ugly).
|
||||
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, cc_data, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
|
||||
}
|
||||
@@ -287,7 +287,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
|
||||
|
||||
ctx->stat_dishheaders++;
|
||||
// ctx->stat_dishheaders++;
|
||||
|
||||
read_bytes(ustream, 2); // "05 02"
|
||||
|
||||
@@ -346,7 +346,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
|
||||
dishdata[cc_count*3] = 0xFF; // Set end marker
|
||||
|
||||
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
|
||||
|
||||
// Ignore 3 (0x0A, followed by two unknown) bytes.
|
||||
break;
|
||||
@@ -371,7 +371,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
|
||||
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
|
||||
|
||||
// Ignore 4 (0x020A, followed by two unknown) bytes.
|
||||
break;
|
||||
@@ -436,7 +436,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
}
|
||||
|
||||
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub);
|
||||
|
||||
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
|
||||
break;
|
||||
@@ -452,7 +452,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
|
||||
{
|
||||
// Either a documentation or more examples are needed.
|
||||
ctx->stat_divicom++;
|
||||
// ctx->stat_divicom++;
|
||||
|
||||
unsigned char data[3];
|
||||
|
||||
@@ -462,7 +462,7 @@ int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, st
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
do_cb(ctx, data, sub);
|
||||
// This is probably incomplete!
|
||||
}
|
||||
else
|
||||
|
||||
92
src/lib_ccx/file_buffer.h
Normal file
92
src/lib_ccx/file_buffer.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#ifndef FILE_BUFFER_H
|
||||
#define FILE_BUFFER_H
|
||||
|
||||
/**
|
||||
* Read from buffer if there is insufficient data then cache the buffer
|
||||
*
|
||||
* @param ctx ccx_demuxer context properly initilaized ccx_demuxer with some input
|
||||
* Not to be NULL, since ctx is derefrenced inside this function
|
||||
*
|
||||
* @param buffer if buffer then it must be allocated to at;east bytes len as
|
||||
* passed in third argument, If buffer is NULL then those number of bytes
|
||||
* are skipped from input.
|
||||
* @param bytes number of bytes to be read from file buffer.
|
||||
*
|
||||
* @return 0 or number of bytes, if returned 0 then op should check error number to know
|
||||
* details of error
|
||||
*/
|
||||
size_t buffered_read_opt (struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes);
|
||||
|
||||
|
||||
/**
|
||||
* Skip bytes from file buffer and if needed also seek file for number of bytes.
|
||||
*
|
||||
*/
|
||||
static size_t inline buffered_skip(struct ccx_demuxer *ctx, unsigned int bytes)
|
||||
{
|
||||
size_t result;
|
||||
if (bytes <= ctx->bytesinbuffer - ctx->filebuffer_pos)
|
||||
{
|
||||
ctx->filebuffer_pos += bytes;
|
||||
result = bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = buffered_read_opt (ctx, NULL, bytes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read bytes from file buffer and if needed also read file for number of bytes.
|
||||
*
|
||||
*/
|
||||
static size_t inline buffered_read(struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes)
|
||||
{
|
||||
size_t result;
|
||||
if (bytes <= ctx->bytesinbuffer - ctx->filebuffer_pos)
|
||||
{
|
||||
if (buffer != NULL)
|
||||
memcpy (buffer, ctx->filebuffer + ctx->filebuffer_pos, bytes);
|
||||
ctx->filebuffer_pos+=bytes;
|
||||
result = bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = buffered_read_opt (ctx, buffer, bytes);
|
||||
if (ccx_options.gui_mode_reports && ccx_options.input_source == CCX_DS_NETWORK)
|
||||
{
|
||||
net_activity_gui++;
|
||||
if (!(net_activity_gui%1000))
|
||||
activity_report_data_read();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read single byte from file buffer and if needed also read file for number of bytes.
|
||||
*
|
||||
*/
|
||||
static size_t inline buffered_read_byte(struct ccx_demuxer *ctx, unsigned char *buffer)
|
||||
{
|
||||
size_t result;
|
||||
if (ctx->bytesinbuffer - ctx->filebuffer_pos)
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
*buffer=ctx->filebuffer[ctx->filebuffer_pos];
|
||||
ctx->filebuffer_pos++;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = buffered_read_opt (ctx, buffer, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned short buffered_get_be16(struct ccx_demuxer *ctx);
|
||||
unsigned char buffered_get_byte (struct ccx_demuxer *ctx);
|
||||
unsigned int buffered_get_be32(struct ccx_demuxer *ctx);
|
||||
#endif
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "activity.h"
|
||||
#include "file_buffer.h"
|
||||
long FILEBUFFERSIZE = 1024*1024*16; // 16 Mbytes no less. Minimize number of real read calls()
|
||||
LLONG buffered_read_opt_file (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData = {0};
|
||||
@@ -11,12 +12,12 @@ int iResult = 0;
|
||||
LLONG getfilesize (int in)
|
||||
{
|
||||
int ret = 0;
|
||||
LLONG current=LSEEK (in, 0, SEEK_CUR);
|
||||
LLONG length = LSEEK (in,0,SEEK_END);
|
||||
LLONG current = LSEEK (in, 0, SEEK_CUR);
|
||||
LLONG length = LSEEK (in, 0, SEEK_END);
|
||||
if(current < 0 ||length < 0)
|
||||
return -1;
|
||||
|
||||
ret = LSEEK (in,current,SEEK_SET);
|
||||
ret = LSEEK (in, current, SEEK_SET);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
@@ -27,22 +28,22 @@ LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files fai
|
||||
{
|
||||
LLONG ts=0;
|
||||
int h;
|
||||
for (int i=0;i<ctx->num_input_files;i++)
|
||||
for (int i = 0; i < ctx->num_input_files; i++)
|
||||
{
|
||||
if (0 == strcmp(ctx->inputfile[i],"-")) // Skip stdin
|
||||
if (0 == strcmp(ctx->inputfile[i], "-")) // Skip stdin
|
||||
continue;
|
||||
#ifdef _WIN32
|
||||
h=OPEN (ctx->inputfile[i],O_RDONLY | O_BINARY);
|
||||
h = OPEN (ctx->inputfile[i], O_RDONLY | O_BINARY);
|
||||
#else
|
||||
h=OPEN (ctx->inputfile[i],O_RDONLY);
|
||||
h = OPEN (ctx->inputfile[i], O_RDONLY);
|
||||
#endif
|
||||
if (h==-1)
|
||||
if (h == -1)
|
||||
{
|
||||
mprint ("\rUnable to open %s\r\n",ctx->inputfile[i]);
|
||||
mprint ("\rUnable to open %s\r\n", ctx->inputfile[i]);
|
||||
return -1;
|
||||
}
|
||||
if (!ccx_options.live_stream)
|
||||
ts+=getfilesize (h);
|
||||
ts += getfilesize (h);
|
||||
close (h);
|
||||
}
|
||||
return ts;
|
||||
@@ -50,64 +51,44 @@ LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files fai
|
||||
|
||||
void prepare_for_new_file (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
// Init per file variables
|
||||
min_pts=0x01FFFFFFFFLL; // 33 bit
|
||||
sync_pts=0;
|
||||
pts_set = 0;
|
||||
// inputsize=0; Now responsibility of switch_to_next_file()
|
||||
ctx->last_reported_progress=-1;
|
||||
ctx->stat_numuserheaders = 0;
|
||||
ctx->stat_dvdccheaders = 0;
|
||||
ctx->stat_scte20ccheaders = 0;
|
||||
ctx->last_reported_progress =-1;
|
||||
ctx->stat_numuserheaders = 0;
|
||||
ctx->stat_dvdccheaders = 0;
|
||||
ctx->stat_scte20ccheaders = 0;
|
||||
ctx->stat_replay5000headers = 0;
|
||||
ctx->stat_replay4000headers = 0;
|
||||
ctx->stat_dishheaders = 0;
|
||||
ctx->stat_hdtv = 0;
|
||||
ctx->stat_divicom = 0;
|
||||
total_frames_count = 0;
|
||||
ctx->total_pulldownfields = 0;
|
||||
ctx->total_pulldownframes = 0;
|
||||
dec_ctx->cc_stats[0]=0; dec_ctx->cc_stats[1]=0; dec_ctx->cc_stats[2]=0; dec_ctx->cc_stats[3]=0;
|
||||
ctx->false_pict_header=0;
|
||||
ctx->frames_since_last_gop=0;
|
||||
frames_since_ref_time=0;
|
||||
gop_time.inited=0;
|
||||
first_gop_time.inited=0;
|
||||
gop_rollover=0;
|
||||
printed_gop.inited=0;
|
||||
dec_ctx->saw_caption_block=0;
|
||||
ctx->past=0;
|
||||
pts_big_change=0;
|
||||
ctx->startbytes_pos=0;
|
||||
ctx->startbytes_avail=0;
|
||||
init_file_buffer();
|
||||
anchor_hdcc(-1);
|
||||
firstcall = 1;
|
||||
for(int x=0; x<0xfff; x++)
|
||||
ctx->stat_dishheaders = 0;
|
||||
ctx->stat_hdtv = 0;
|
||||
ctx->stat_divicom = 0;
|
||||
total_frames_count = 0;
|
||||
ctx->false_pict_header = 0;
|
||||
frames_since_ref_time = 0;
|
||||
gop_time.inited = 0;
|
||||
first_gop_time.inited = 0;
|
||||
gop_rollover = 0;
|
||||
printed_gop.inited = 0;
|
||||
pts_big_change = 0;
|
||||
firstcall = 1;
|
||||
|
||||
for(int x = 0; x < 0xfff; x++)
|
||||
{
|
||||
ctx->epg_buffers[x].buffer=NULL;
|
||||
ctx->epg_buffers[x].ccounter=0;
|
||||
ctx->epg_buffers[x].buffer = NULL;
|
||||
ctx->epg_buffers[x].ccounter = 0;
|
||||
}
|
||||
for (int i = 0; i < TS_PMT_MAP_SIZE; i++)
|
||||
{
|
||||
ctx->eit_programs[i].array_len=0;
|
||||
ctx->eit_current_events[i]=-1;
|
||||
ctx->eit_programs[i].array_len = 0;
|
||||
ctx->eit_current_events[i] = -1;
|
||||
}
|
||||
ctx->epg_last_output=-1;
|
||||
ctx->epg_last_live_output=-1;
|
||||
ctx->epg_last_output = -1;
|
||||
ctx->epg_last_live_output = -1;
|
||||
}
|
||||
|
||||
/* Close input file if there is one and let the GUI know */
|
||||
void close_input_file (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
if (ctx->infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
|
||||
{
|
||||
close (ctx->infd);
|
||||
ctx->infd=-1;
|
||||
activity_input_file_closed();
|
||||
}
|
||||
ctx->demux_ctx->close(ctx->demux_ctx);
|
||||
}
|
||||
|
||||
/* Close current file and open next one in list -if any- */
|
||||
@@ -117,223 +98,206 @@ can be done */
|
||||
|
||||
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
if (ctx->current_file==-1 || !ccx_options.binary_concat)
|
||||
int ret = 0;
|
||||
if (ctx->current_file == -1 || !ccx_options.binary_concat)
|
||||
{
|
||||
memset (ctx->PIDs_seen,0,65536*sizeof (int));
|
||||
memset (ctx->PIDs_programs,0,65536*sizeof (struct PMT_entry *));
|
||||
ctx->demux_ctx->reset(ctx->demux_ctx);
|
||||
}
|
||||
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
switch(ccx_options.input_source)
|
||||
{
|
||||
if (ctx->infd!=-1) // Means we had already processed stdin. So we're done.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx);
|
||||
return 0;
|
||||
}
|
||||
ctx->infd=0;
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rReading from standard input\n");
|
||||
return 1;
|
||||
case CCX_DS_STDIN:
|
||||
case CCX_DS_NETWORK:
|
||||
case CCX_DS_TCP:
|
||||
ret = ctx->demux_ctx->open(ctx->demux_ctx, NULL);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
else if (ret)
|
||||
return ret;
|
||||
else
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ccx_options.input_source==CCX_DS_NETWORK)
|
||||
/* Close current and make sure things are still sane */
|
||||
if (ctx->demux_ctx->is_open(ctx->demux_ctx))
|
||||
{
|
||||
if (ctx->infd!=-1) // Means we have already bound a socket.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
|
||||
if(ctx->infd < 0)
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "socket() failed.");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
if (ccx_options.input_source==CCX_DS_TCP)
|
||||
{
|
||||
if (ctx->infd != -1)
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Close current and make sure things are still sane */
|
||||
if (ctx->infd!=-1)
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report(ctx);
|
||||
close_input_file (ctx);
|
||||
if (ctx->inputsize>0 && ((ctx->past+bytesinbuffer) < ctx->inputsize) && !dec_ctx->processed_enough)
|
||||
|
||||
if (ctx->inputsize > 0 && ((ctx->demux_ctx->past+bytesinbuffer) < ctx->inputsize) && is_decoder_processed_enough(ctx) == CCX_FALSE)
|
||||
{
|
||||
mprint("\n\n\n\nATTENTION!!!!!!\n");
|
||||
mprint("In switch_to_next_file(): Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
|
||||
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->past, ctx->inputsize);
|
||||
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->demux_ctx->past, ctx->inputsize);
|
||||
}
|
||||
close_input_file (ctx);
|
||||
|
||||
if (ccx_options.binary_concat)
|
||||
{
|
||||
ctx->total_past+=ctx->inputsize;
|
||||
ctx->past=0; // Reset always or at the end we'll have double the size
|
||||
ctx->total_past += ctx->inputsize;
|
||||
ctx->demux_ctx->past = 0; // Reset always or at the end we'll have double the size
|
||||
}
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
ctx->current_file++;
|
||||
if (ctx->current_file>=ctx->num_input_files)
|
||||
break;
|
||||
|
||||
// The following \n keeps the progress percentage from being overwritten.
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rOpening file: %s\n", ctx->inputfile[ctx->current_file]);
|
||||
#ifdef _WIN32
|
||||
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY | O_BINARY);
|
||||
#else
|
||||
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY);
|
||||
#endif
|
||||
if (ctx->infd == -1)
|
||||
mprint ("\rWarning: Unable to open input file [%s]\n", ctx->inputfile[ctx->current_file]);
|
||||
else
|
||||
{
|
||||
activity_input_file_open (ctx->inputfile[ctx->current_file]);
|
||||
if (!ccx_options.live_stream)
|
||||
{
|
||||
ctx->inputsize = getfilesize (ctx->infd);
|
||||
if (!ccx_options.binary_concat)
|
||||
ctx->total_inputsize=ctx->inputsize;
|
||||
}
|
||||
return 1; // Succeeded
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void position_sanity_check (void)
|
||||
{
|
||||
#ifdef SANITY_CHECK
|
||||
if (in!=-1)
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
LLONG realpos=LSEEK (in,0,SEEK_CUR);
|
||||
if (realpos!=ctx->past-filebuffer_pos+bytesinbuffer)
|
||||
ctx->current_file++;
|
||||
if (ctx->current_file >= ctx->num_input_files)
|
||||
break;
|
||||
|
||||
// The following \n keeps the progress percentage from being overwritten.
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rOpening file: %s\n", ctx->inputfile[ctx->current_file]);
|
||||
ret = ctx->demux_ctx->open(ctx->demux_ctx, ctx->inputfile[ctx->current_file]);
|
||||
if (ret < 0)
|
||||
mprint ("\rWarning: Unable to open input file [%s]\n", ctx->inputfile[ctx->current_file]);
|
||||
else
|
||||
{
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,ctx->past);
|
||||
activity_input_file_open (ctx->inputfile[ctx->current_file]);
|
||||
if (!ccx_options.live_stream)
|
||||
{
|
||||
ctx->inputsize = ctx->demux_ctx->get_filesize (ctx->demux_ctx);
|
||||
if (!ccx_options.binary_concat)
|
||||
ctx->total_inputsize = ctx->inputsize;
|
||||
}
|
||||
return 1; // Succeeded
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int init_file_buffer(void)
|
||||
{
|
||||
filebuffer_start=0;
|
||||
filebuffer_pos=0;
|
||||
if (filebuffer==NULL)
|
||||
{
|
||||
filebuffer=(unsigned char *) malloc (FILEBUFFERSIZE);
|
||||
bytesinbuffer=0;
|
||||
}
|
||||
if (filebuffer==NULL)
|
||||
{
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buffered_seek (struct lib_ccx_ctx *ctx, int offset)
|
||||
void position_sanity_check (int in)
|
||||
{
|
||||
position_sanity_check();
|
||||
if (offset<0)
|
||||
#ifdef SANITY_CHECK
|
||||
if (in!=-1)
|
||||
{
|
||||
filebuffer_pos+=offset;
|
||||
if (filebuffer_pos<0)
|
||||
LLONG realpos = LSEEK (in,0,SEEK_CUR);
|
||||
if (realpos != ctx->demux_ctx->past - filebuffer_pos + bytesinbuffer)
|
||||
{
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n", realpos, ctx->demux_ctx->past);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int init_file_buffer(struct ccx_demuxer *ctx)
|
||||
{
|
||||
ctx->filebuffer_start = 0;
|
||||
ctx->filebuffer_pos = 0;
|
||||
if (ctx->filebuffer == NULL)
|
||||
{
|
||||
ctx->filebuffer = (unsigned char *) malloc (FILEBUFFERSIZE);
|
||||
ctx->bytesinbuffer = 0;
|
||||
}
|
||||
if (ctx->filebuffer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buffered_seek (struct ccx_demuxer *ctx, int offset)
|
||||
{
|
||||
position_sanity_check(ctx->infd);
|
||||
if (offset < 0)
|
||||
{
|
||||
ctx->filebuffer_pos += offset;
|
||||
if (ctx->filebuffer_pos < 0)
|
||||
{
|
||||
// We got into the start buffer (hopefully)
|
||||
if ((filebuffer_pos+ctx->startbytes_pos) < 0)
|
||||
if ((ctx->filebuffer_pos + ctx->startbytes_pos) < 0)
|
||||
{
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
|
||||
}
|
||||
ctx->startbytes_pos+=filebuffer_pos;
|
||||
filebuffer_pos=0;
|
||||
ctx->startbytes_pos += ctx->filebuffer_pos;
|
||||
ctx->filebuffer_pos = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read_opt (ctx, NULL, offset);
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
}
|
||||
}
|
||||
|
||||
void sleepandchecktimeout (time_t start)
|
||||
{
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
if (ccx_options.input_source == CCX_DS_STDIN)
|
||||
{
|
||||
// CFS: Not 100% sure about this. Fine for files, not so sure what happens if stdin is
|
||||
// real time input from hardware.
|
||||
sleep_secs (1);
|
||||
ccx_options.live_stream=0;
|
||||
ccx_options.live_stream = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ccx_options.live_stream==-1) // Just sleep, no timeout to check
|
||||
if (ccx_options.live_stream == -1) // Just sleep, no timeout to check
|
||||
{
|
||||
sleep_secs (1);
|
||||
return;
|
||||
}
|
||||
if (time(NULL)>start+ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
|
||||
ccx_options.live_stream=0;
|
||||
if (time(NULL) > start + ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
|
||||
ccx_options.live_stream = 0;
|
||||
else
|
||||
sleep_secs(1);
|
||||
}
|
||||
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes)
|
||||
void return_to_buffer (struct ccx_demuxer *ctx, unsigned char *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes == filebuffer_pos)
|
||||
if (bytes == ctx->filebuffer_pos)
|
||||
{
|
||||
// Usually we're just going back in the buffer and memcpy would be
|
||||
// unnecessary, but we do it in case we intentionally messed with the
|
||||
// buffer
|
||||
memcpy (filebuffer, buffer, bytes);
|
||||
filebuffer_pos=0;
|
||||
memcpy (ctx->filebuffer, buffer, bytes);
|
||||
ctx->filebuffer_pos = 0;
|
||||
return;
|
||||
}
|
||||
if (filebuffer_pos>0) // Discard old bytes, because we may need the space
|
||||
if (ctx->filebuffer_pos > 0) // Discard old bytes, because we may need the space
|
||||
{
|
||||
// Non optimal since data is moved later again but we don't care since
|
||||
// we're never here in ccextractor.
|
||||
memmove (filebuffer,filebuffer+filebuffer_pos,bytesinbuffer-filebuffer_pos);
|
||||
bytesinbuffer-=filebuffer_pos;
|
||||
bytesinbuffer=0;
|
||||
filebuffer_pos=0;
|
||||
memmove (ctx->filebuffer, ctx->filebuffer + ctx->filebuffer_pos, ctx->bytesinbuffer-ctx->filebuffer_pos);
|
||||
ctx->bytesinbuffer -= ctx->filebuffer_pos;
|
||||
ctx->bytesinbuffer = 0;
|
||||
ctx->filebuffer_pos = 0;
|
||||
}
|
||||
|
||||
if (bytesinbuffer + bytes > FILEBUFFERSIZE)
|
||||
if (ctx->bytesinbuffer + bytes > FILEBUFFERSIZE)
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Invalid return_to_buffer() - please submit a bug report.");
|
||||
memmove (filebuffer+bytes,filebuffer,bytesinbuffer);
|
||||
memcpy (filebuffer,buffer,bytes);
|
||||
bytesinbuffer+=bytes;
|
||||
|
||||
memmove (ctx->filebuffer + bytes, ctx->filebuffer, ctx->bytesinbuffer);
|
||||
memcpy (ctx->filebuffer, buffer, bytes);
|
||||
ctx->bytesinbuffer += bytes;
|
||||
}
|
||||
|
||||
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes)
|
||||
/**
|
||||
* @param buffer can be NULL, in case when user want to just buffer it or skip some data.
|
||||
*
|
||||
* Global options that have efffect on this function are following
|
||||
* 1) ccx_options.live_stream
|
||||
* 2) ccx_options.buffer_input
|
||||
* 3) ccx_options.input_source
|
||||
* 4) ccx_options.binary_concat
|
||||
*
|
||||
* TODO instead of using global ccx_options move them to ccx_demuxer
|
||||
*/
|
||||
size_t buffered_read_opt (struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes)
|
||||
{
|
||||
LLONG copied=0;
|
||||
position_sanity_check();
|
||||
time_t seconds=0;
|
||||
if (ccx_options.live_stream>0)
|
||||
size_t copied = 0;
|
||||
time_t seconds = 0;
|
||||
|
||||
position_sanity_check(ctx->infd);
|
||||
|
||||
if (ccx_options.live_stream > 0)
|
||||
time (&seconds);
|
||||
if (ccx_options.buffer_input || filebuffer_pos<bytesinbuffer)
|
||||
|
||||
if (ccx_options.buffer_input || ctx->filebuffer_pos < ctx->bytesinbuffer)
|
||||
{
|
||||
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
|
||||
int eof = (ctx->infd==-1);
|
||||
int eof = (ctx->infd == -1);
|
||||
|
||||
while ((!eof || ccx_options.live_stream) && bytes)
|
||||
{
|
||||
@@ -343,8 +307,8 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
|
||||
// for the data to come up
|
||||
sleepandchecktimeout (seconds);
|
||||
}
|
||||
size_t ready = bytesinbuffer-filebuffer_pos;
|
||||
if (ready==0) // We really need to read more
|
||||
size_t ready = ctx->bytesinbuffer - ctx->filebuffer_pos;
|
||||
if (ready == 0) // We really need to read more
|
||||
{
|
||||
if (!ccx_options.buffer_input)
|
||||
{
|
||||
@@ -356,25 +320,27 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
|
||||
{
|
||||
// No code for network support here, because network is always
|
||||
// buffered - if here, then it must be files.
|
||||
if (buffer!=NULL) // Read
|
||||
if (buffer != NULL) // Read
|
||||
{
|
||||
i=read (ctx->infd,buffer,bytes);
|
||||
i = read (ctx->infd, buffer, bytes);
|
||||
if( i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
buffer+=i;
|
||||
buffer += i;
|
||||
}
|
||||
else // Seek
|
||||
{
|
||||
LLONG op, np;
|
||||
op =LSEEK (ctx->infd,0,SEEK_CUR); // Get current pos
|
||||
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
|
||||
op = LSEEK (ctx->infd, 0, SEEK_CUR); // Get current pos
|
||||
if (op + bytes < 0) // Would mean moving beyond start of file: Not supported
|
||||
return 0;
|
||||
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
|
||||
i=(int) (np-op);
|
||||
np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving
|
||||
i = (int) (np - op);
|
||||
}
|
||||
if (i==0 && ccx_options.live_stream)
|
||||
// if both above lseek returned -1 (error); i would be 0 here and
|
||||
// in case when its not live stream copied would decrease and bytes would...
|
||||
if (i == 0 && ccx_options.live_stream)
|
||||
{
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
if (ccx_options.input_source == CCX_DS_STDIN)
|
||||
{
|
||||
ccx_options.live_stream = 0;
|
||||
break;
|
||||
@@ -386,35 +352,37 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
|
||||
}
|
||||
else
|
||||
{
|
||||
copied+=i;
|
||||
bytes-=i;
|
||||
copied += i;
|
||||
bytes -= i;
|
||||
}
|
||||
|
||||
}
|
||||
while ((i || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))) && bytes);
|
||||
(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied))) && bytes);
|
||||
return copied;
|
||||
}
|
||||
// Keep the last 8 bytes, so we have a guaranteed
|
||||
// working seek (-8) - needed by mythtv.
|
||||
int keep = bytesinbuffer > 8 ? 8 : bytesinbuffer;
|
||||
memmove (filebuffer,filebuffer+(FILEBUFFERSIZE-keep),keep);
|
||||
int keep = ctx->bytesinbuffer > 8 ? 8 : ctx->bytesinbuffer;
|
||||
memmove (ctx->filebuffer, ctx->filebuffer+(FILEBUFFERSIZE-keep),keep);
|
||||
int i;
|
||||
if (ccx_options.input_source==CCX_DS_FILE || ccx_options.input_source==CCX_DS_STDIN)
|
||||
i = read (ctx->infd, filebuffer+keep,FILEBUFFERSIZE-keep);
|
||||
if (ccx_options.input_source == CCX_DS_FILE || ccx_options.input_source == CCX_DS_STDIN)
|
||||
i = read (ctx->infd, ctx->filebuffer + keep, FILEBUFFERSIZE-keep);
|
||||
else if (ccx_options.input_source == CCX_DS_TCP)
|
||||
i = net_tcp_read(ctx->infd, (char *) ctx->filebuffer + keep, FILEBUFFERSIZE - keep);
|
||||
else
|
||||
i = recvfrom(ctx->infd,(char *) filebuffer + keep, FILEBUFFERSIZE - keep, 0, NULL, NULL);
|
||||
i = recvfrom(ctx->infd,(char *) ctx->filebuffer + keep, FILEBUFFERSIZE - keep, 0, NULL, NULL);
|
||||
if (i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input stream!\n");
|
||||
if (i == 0)
|
||||
{
|
||||
/* If live stream, don't try to switch - acknowledge eof here as it won't
|
||||
cause a loop end */
|
||||
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx, copied)))
|
||||
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied)))
|
||||
eof = 1;
|
||||
}
|
||||
filebuffer_pos = keep;
|
||||
bytesinbuffer=(int) i + keep;
|
||||
ctx->filebuffer_pos = keep;
|
||||
ctx->bytesinbuffer = (int) i + keep;
|
||||
ready = i;
|
||||
}
|
||||
int copy = (int) (ready>=bytes ? bytes:ready);
|
||||
@@ -422,63 +390,97 @@ LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigne
|
||||
{
|
||||
if (buffer != NULL)
|
||||
{
|
||||
memcpy (buffer, filebuffer+filebuffer_pos, copy);
|
||||
buffer+=copy;
|
||||
memcpy (buffer, ctx->filebuffer + ctx->filebuffer_pos, copy);
|
||||
buffer += copy;
|
||||
}
|
||||
filebuffer_pos+=copy;
|
||||
bytes-=copy;
|
||||
copied+=copy;
|
||||
ctx->filebuffer_pos += copy;
|
||||
bytes -= copy;
|
||||
copied += copy;
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
else // Read without buffering
|
||||
{
|
||||
|
||||
if (buffer!=NULL)
|
||||
if (buffer != NULL)
|
||||
{
|
||||
int i;
|
||||
while (bytes>0 && ctx->infd!=-1 &&
|
||||
((i=read(ctx->infd,buffer,bytes))!=0 || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))))
|
||||
while (bytes > 0 && ctx->infd != -1 &&
|
||||
((i = read(ctx->infd, buffer, bytes)) != 0 || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied))))
|
||||
{
|
||||
if( i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
else if (i==0)
|
||||
else if (i == 0)
|
||||
sleepandchecktimeout (seconds);
|
||||
else
|
||||
{
|
||||
copied+=i;
|
||||
bytes-=i;
|
||||
buffer+=i;
|
||||
copied += i;
|
||||
bytes -= i;
|
||||
buffer += i;
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
// return fread(buffer,1,bytes,in);
|
||||
//return FSEEK (in,bytes,SEEK_CUR);
|
||||
while (bytes!=0 && ctx->infd!=-1)
|
||||
while (bytes != 0 && ctx->infd != -1)
|
||||
{
|
||||
LLONG op, np;
|
||||
op =LSEEK (ctx->infd,0,SEEK_CUR); // Get current pos
|
||||
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
|
||||
op = LSEEK (ctx->infd, 0, SEEK_CUR); // Get current pos
|
||||
if (op + bytes < 0) // Would mean moving beyond start of file: Not supported
|
||||
return 0;
|
||||
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
|
||||
copied=copied+(np-op);
|
||||
bytes=bytes-(unsigned int) copied;
|
||||
if (copied==0)
|
||||
|
||||
np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving
|
||||
copied = copied + (np - op);
|
||||
bytes = bytes- (unsigned int) copied;
|
||||
if (copied == 0)
|
||||
{
|
||||
if (ccx_options.live_stream)
|
||||
sleepandchecktimeout (seconds);
|
||||
else
|
||||
{
|
||||
if (ccx_options.binary_concat)
|
||||
switch_to_next_file(ctx, 0);
|
||||
switch_to_next_file(ctx->parent, 0);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
unsigned short buffered_get_be16(struct ccx_demuxer *ctx)
|
||||
{
|
||||
unsigned char a,b;
|
||||
unsigned char *a_p = &a; // Just to suppress warnings
|
||||
unsigned char *b_p = &b;
|
||||
buffered_read_byte(ctx, a_p);
|
||||
ctx->past++;
|
||||
buffered_read_byte(ctx, b_p);
|
||||
ctx->past++;
|
||||
return ( (unsigned short) (a<<8) )| ( (unsigned short) b);
|
||||
}
|
||||
|
||||
unsigned char buffered_get_byte (struct ccx_demuxer *ctx)
|
||||
{
|
||||
unsigned char b;
|
||||
unsigned char *b_p = &b;
|
||||
size_t result;
|
||||
|
||||
result = buffered_read_byte(ctx, b_p);
|
||||
if (result == 1)
|
||||
{
|
||||
ctx->past++;
|
||||
return b;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int buffered_get_be32(struct ccx_demuxer *ctx)
|
||||
{
|
||||
unsigned int val;
|
||||
val = buffered_get_be16(ctx) << 16;
|
||||
val |= buffered_get_be16(ctx);
|
||||
return val;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,10 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "activity.h"
|
||||
#include "utility.h"
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "ccx_decoders_isdb.h"
|
||||
|
||||
struct ccx_common_logging_t ccx_common_logging;
|
||||
static struct ccx_decoders_common_settings_t *init_decoder_setting(
|
||||
@@ -16,13 +21,17 @@ static struct ccx_decoders_common_settings_t *init_decoder_setting(
|
||||
setting->fix_padding = opt->fix_padding;
|
||||
setting->extract = opt->extract;
|
||||
setting->fullbin = opt->fullbin;
|
||||
setting->no_rollup = opt->no_rollup;
|
||||
memcpy(&setting->extraction_start,&opt->extraction_start,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&setting->extraction_end,&opt->extraction_end,sizeof(struct ccx_boundary_time));
|
||||
setting->cc_to_stdout = opt->cc_to_stdout;
|
||||
setting->settings_608 = &opt->settings_608;
|
||||
setting->settings_dtvcc = &opt->settings_dtvcc;
|
||||
setting->cc_channel = opt->cc_channel;
|
||||
setting->trim_subs = opt->trim_subs;
|
||||
setting->send_to_srv = opt->send_to_srv;
|
||||
setting->hauppauge_mode = opt->hauppauge_mode;
|
||||
/* if in transcript setting xds is not selected then set ignore xds flag */
|
||||
setting->ignore_xds = !opt->transcript_settings.xds;
|
||||
return setting;
|
||||
}
|
||||
static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setting)
|
||||
@@ -31,121 +40,77 @@ static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setti
|
||||
}
|
||||
|
||||
|
||||
static int init_ctx_input(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
|
||||
static int init_ctx_outbase(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int len;
|
||||
char *file,*c;
|
||||
char *file;
|
||||
|
||||
switch (opt->input_source)
|
||||
if (opt->output_filename)
|
||||
{
|
||||
case CCX_DS_FILE:
|
||||
if(!ctx->inputfile || !ctx->inputfile[0]) {
|
||||
ctx->basefilename = get_basename(opt->output_filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (opt->input_source)
|
||||
{
|
||||
case CCX_DS_FILE:
|
||||
if(!ctx->inputfile || !ctx->inputfile[0])
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
file = ctx->inputfile[0];
|
||||
break;
|
||||
case CCX_DS_STDIN:
|
||||
file = "stdin";
|
||||
break;
|
||||
case CCX_DS_NETWORK:
|
||||
case CCX_DS_TCP:
|
||||
file = "network";
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
len = strlen (ctx->inputfile[0]) + 1;
|
||||
file = ctx->inputfile[0];
|
||||
break;
|
||||
case CCX_DS_STDIN:
|
||||
len = strlen ("stdin") + 1;
|
||||
file = "stdin";
|
||||
break;
|
||||
case CCX_DS_NETWORK:
|
||||
case CCX_DS_TCP:
|
||||
len = strlen ("network") + 1;
|
||||
file = "network";
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->basefilename = get_basename(file);
|
||||
}
|
||||
|
||||
ctx->basefilename = (char *) malloc(len);
|
||||
if (ctx->basefilename == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy (ctx->basefilename, file);
|
||||
|
||||
for (c = ctx->basefilename + len - 1; c > ctx->basefilename && *c != '.'; c--)
|
||||
{;} // Get last .
|
||||
if (*c == '.')
|
||||
*c = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_ctx_extension(struct ccx_s_options *opt, struct lib_ccx_ctx *ctx)
|
||||
struct encoder_ctx *get_encoder_by_pn(struct lib_ccx_ctx *ctx, int pn)
|
||||
{
|
||||
switch (opt->write_format)
|
||||
struct encoder_ctx *enc_ctx;
|
||||
list_for_each_entry(enc_ctx, &ctx->enc_ctx_head, list, struct encoder_ctx)
|
||||
{
|
||||
case CCX_OF_RAW:
|
||||
ctx->extension = ".raw";
|
||||
break;
|
||||
case CCX_OF_SRT:
|
||||
ctx->extension = ".srt";
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
ctx->extension = ".smi";
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
ctx->extension = ".ttml";
|
||||
break;
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
ctx->extension = ".txt";
|
||||
break;
|
||||
case CCX_OF_RCWT:
|
||||
ctx->extension = ".bin";
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
ctx->extension = ".xml";
|
||||
break;
|
||||
case CCX_OF_NULL:
|
||||
ctx->extension = "";
|
||||
break;
|
||||
case CCX_OF_DVDRAW:
|
||||
ctx->extension = ".dvdraw";
|
||||
break;
|
||||
default:
|
||||
mprint ("write_format doesn't have any legal value, this is a bug.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
if (enc_ctx->program_number == pn)
|
||||
return enc_ctx;
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
|
||||
{
|
||||
int ret = 0;
|
||||
struct lib_ccx_ctx *ctx;
|
||||
struct ccx_decoder_608_report *report_608;
|
||||
struct ccx_decoders_common_settings_t *dec_setting;
|
||||
|
||||
ctx = malloc(sizeof(struct lib_ccx_ctx));
|
||||
struct lib_ccx_ctx *ctx = malloc(sizeof(struct lib_ccx_ctx));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
memset(ctx,0,sizeof(struct lib_ccx_ctx));
|
||||
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "lib_ccx_ctx");
|
||||
memset(ctx, 0, sizeof(struct lib_ccx_ctx));
|
||||
|
||||
report_608 = malloc(sizeof(struct ccx_decoder_608_report));
|
||||
struct ccx_decoder_608_report *report_608 = malloc(sizeof(struct ccx_decoder_608_report));
|
||||
if (!report_608)
|
||||
return NULL;
|
||||
memset(report_608,0,sizeof(struct ccx_decoder_608_report));
|
||||
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "report_608");
|
||||
memset(report_608, 0, sizeof(struct ccx_decoder_608_report));
|
||||
|
||||
ctx->capbufsize = 20000;
|
||||
ctx->capbuf = NULL;
|
||||
ctx->capbuflen = 0; // Bytes read in capbuf
|
||||
ccx_decoder_dtvcc_report *report_dtvcc = (ccx_decoder_dtvcc_report *)
|
||||
malloc(sizeof(ccx_decoder_dtvcc_report));
|
||||
if (!report_dtvcc)
|
||||
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "report_dtvcc");
|
||||
memset(report_dtvcc, 0, sizeof(ccx_decoder_dtvcc_report));
|
||||
|
||||
// Initialize some constants
|
||||
init_ts(ctx);
|
||||
init_avc();
|
||||
|
||||
ctx->stream_mode = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
ctx->auto_stream = opt->auto_stream;
|
||||
ctx->m2ts = opt->m2ts;
|
||||
ctx->screens_to_process = -1;
|
||||
ctx->current_file = -1;
|
||||
ctx->infd = -1;//Set to -1 to indicate no file is open.
|
||||
|
||||
// Set logging functions for libraries
|
||||
ccx_common_logging.debug_ftn = &dbg_print;
|
||||
@@ -154,51 +119,29 @@ struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
|
||||
ccx_common_logging.log_ftn = &mprint;
|
||||
ccx_common_logging.gui_ftn = &activity_library_process;
|
||||
|
||||
// Init shared decoder settings
|
||||
ctx->dec_global_setting = init_decoder_setting(opt);
|
||||
if (!ctx->dec_global_setting)
|
||||
return NULL;
|
||||
|
||||
// Need to set the 608 data for the report to the correct variable.
|
||||
ctx->freport.data_from_608 = report_608;
|
||||
// Same applies for 708 data
|
||||
ctx->freport.data_from_708 = &ccx_decoder_708_report;
|
||||
|
||||
// Init shared decoder settings
|
||||
dec_setting = init_decoder_setting(opt);
|
||||
ctx->dec_ctx = init_cc_decode(dec_setting);
|
||||
dinit_decoder_setting(&dec_setting);
|
||||
|
||||
// Init encoder helper variables
|
||||
ccx_encoders_helpers_setup(opt->encoding, opt->nofontcolor, opt->notypesetting, opt->trim_subs);
|
||||
|
||||
ctx->dec_global_setting->settings_608->report = report_608;
|
||||
ctx->freport.data_from_708 = report_dtvcc;
|
||||
ctx->dec_global_setting->settings_dtvcc->report = report_dtvcc;
|
||||
ctx->mp4_cfg.mp4vidtrack = opt->mp4vidtrack;
|
||||
//Initialize input files
|
||||
ctx->inputfile = opt->inputfile;
|
||||
ctx->num_input_files = opt->num_input_files;
|
||||
|
||||
ret = init_ctx_input(opt, ctx);
|
||||
ret = init_ctx_outbase(opt, ctx);
|
||||
if (ret < 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = init_ctx_extension(opt, ctx);
|
||||
if (ret < 0) {
|
||||
goto end;
|
||||
}
|
||||
// Init 708 decoder(s)
|
||||
ccx_decoders_708_init_library(ctx->basefilename, ctx->extension, opt->print_file_reports);
|
||||
|
||||
// Set output structures for the 608 decoder
|
||||
//ctx->dec_ctx->context_cc608_field_1->out = ctx->dec_ctx->wbout1;
|
||||
//ctx->dec_ctx->context_cc608_field_2->out = ctx->dec_ctx->wbout2;
|
||||
|
||||
// Init XDS buffers
|
||||
ccx_decoders_xds_init_library(&opt->transcript_settings, ctx->subs_delay, opt->millis_separator);
|
||||
//xds_cea608_test();
|
||||
|
||||
ctx->subs_delay = opt->subs_delay;
|
||||
ctx->wbout1.filename = opt->wbout2.filename;
|
||||
ctx->wbout2.filename = opt->wbout2.filename;
|
||||
ctx->buffer = (unsigned char *) malloc (BUFSIZE);
|
||||
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
|
||||
|
||||
// Init timing
|
||||
ccx_common_timing_init(&ctx->past,opt->nosync);
|
||||
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
|
||||
|
||||
ctx->cc_to_stdout = opt->cc_to_stdout;
|
||||
|
||||
@@ -207,8 +150,21 @@ struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
|
||||
ctx->binary_concat = opt->binary_concat;
|
||||
build_parity_table();
|
||||
|
||||
ctx->demux_ctx = init_demuxer(ctx, &opt->demux_cfg);
|
||||
INIT_LIST_HEAD(&ctx->dec_ctx_head);
|
||||
INIT_LIST_HEAD(&ctx->enc_ctx_head);
|
||||
|
||||
// Init timing
|
||||
ccx_common_timing_init(&ctx->demux_ctx->past,opt->nosync);
|
||||
ctx->multiprogram = opt->multiprogram;
|
||||
ctx->write_format = opt->write_format;
|
||||
ctx->out_interval = opt->out_interval;
|
||||
ctx->segment_counter = 0;
|
||||
ctx->system_start_time = -1;
|
||||
|
||||
end:
|
||||
if (ret < 0) {
|
||||
if (ret != EXIT_OK)
|
||||
{
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
@@ -218,18 +174,216 @@ end:
|
||||
void dinit_libraries( struct lib_ccx_ctx **ctx)
|
||||
{
|
||||
struct lib_ccx_ctx *lctx = *ctx;
|
||||
int i = 0;
|
||||
for (i = 0; i < MAX_PID; i++)
|
||||
struct encoder_ctx *enc_ctx;
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
struct lib_cc_decode *dec_ctx1;
|
||||
int i;
|
||||
list_for_each_entry_safe(dec_ctx, dec_ctx1, &lctx->dec_ctx_head, list, struct lib_cc_decode)
|
||||
{
|
||||
if( lctx->PIDs_programs[i])
|
||||
freep(lctx->PIDs_programs + i);
|
||||
LLONG cfts;
|
||||
if (dec_ctx->codec == CCX_CODEC_DVB)
|
||||
dvbsub_close_decoder(&dec_ctx->private_data);
|
||||
//Test memory for teletext
|
||||
//else if (dec_ctx->codec == CCX_CODEC_TELETEXT)
|
||||
// telxcc_close(&dec_ctx->private_data, NULL);
|
||||
else if (dec_ctx->codec == CCX_CODEC_ISDB_CC)
|
||||
delete_isdb_decoder(&dec_ctx->private_data);
|
||||
|
||||
flush_cc_decode(dec_ctx, &dec_ctx->dec_sub);
|
||||
cfts = get_fts(dec_ctx->timing, dec_ctx->current_field);
|
||||
enc_ctx = get_encoder_by_pn(lctx, dec_ctx->program_number);
|
||||
if (enc_ctx && dec_ctx->dec_sub.got_output == CCX_TRUE)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_ctx->dec_sub);
|
||||
dec_ctx->dec_sub.got_output = CCX_FALSE;
|
||||
}
|
||||
list_del(&dec_ctx->list);
|
||||
dinit_cc_decode(&dec_ctx);
|
||||
if (enc_ctx)
|
||||
{
|
||||
list_del(&enc_ctx->list);
|
||||
dinit_encoder(&enc_ctx, cfts);
|
||||
}
|
||||
}
|
||||
|
||||
// free EPG memory
|
||||
EPG_free(lctx);
|
||||
dinit_ts(lctx);
|
||||
dinit_cc_decode(&lctx->dec_ctx);
|
||||
freep(&lctx->buffer);
|
||||
freep(&lctx->pesheaderbuf);
|
||||
freep(&lctx->freport.data_from_608);
|
||||
freep(&lctx->freport.data_from_708);
|
||||
ccx_demuxer_delete(&lctx->demux_ctx);
|
||||
dinit_decoder_setting(&lctx->dec_global_setting);
|
||||
freep(&ccx_options.enc_cfg.output_filename);
|
||||
freep(&lctx->basefilename);
|
||||
freep(&lctx->pesheaderbuf);
|
||||
for(i = 0;i < lctx->num_input_files;i++)
|
||||
freep(&lctx->inputfile[i]);
|
||||
freep(&lctx->inputfile);
|
||||
freep(ctx);
|
||||
}
|
||||
|
||||
int is_decoder_processed_enough(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
|
||||
{
|
||||
if (dec_ctx->processed_enough == CCX_TRUE && ctx->multiprogram == CCX_FALSE)
|
||||
return CCX_TRUE;
|
||||
}
|
||||
|
||||
return CCX_FALSE;
|
||||
}
|
||||
struct lib_cc_decode *update_decoder_list(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
|
||||
{
|
||||
return dec_ctx;
|
||||
}
|
||||
|
||||
if (list_empty(&ctx->dec_ctx_head))
|
||||
{
|
||||
ctx->dec_global_setting->codec = CCX_CODEC_ATSC_CC;
|
||||
ctx->dec_global_setting->program_number = 0;
|
||||
dec_ctx = init_cc_decode(ctx->dec_global_setting);
|
||||
if (!dec_ctx)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
list_add_tail( &(dec_ctx->list), &(ctx->dec_ctx_head) );
|
||||
}
|
||||
return dec_ctx;
|
||||
}
|
||||
|
||||
struct lib_cc_decode *update_decoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
list_for_each_entry(dec_ctx, &ctx->dec_ctx_head, list, struct lib_cc_decode)
|
||||
{
|
||||
if (!cinfo || ctx->multiprogram == CCX_FALSE)
|
||||
return dec_ctx;
|
||||
|
||||
if (dec_ctx->program_number == cinfo->program_number)
|
||||
return dec_ctx;
|
||||
}
|
||||
if(cinfo)
|
||||
{
|
||||
ctx->dec_global_setting->program_number = cinfo->program_number;
|
||||
ctx->dec_global_setting->codec = cinfo->codec;
|
||||
ctx->dec_global_setting->private_data = cinfo->codec_private_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->dec_global_setting->program_number = 0;
|
||||
ctx->dec_global_setting->codec = CCX_CODEC_ATSC_CC;
|
||||
}
|
||||
if(ctx->multiprogram == CCX_FALSE)
|
||||
{
|
||||
if (list_empty(&ctx->dec_ctx_head))
|
||||
{
|
||||
dec_ctx = init_cc_decode(ctx->dec_global_setting);
|
||||
if (!dec_ctx)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
list_add_tail( &(dec_ctx->list), &(ctx->dec_ctx_head) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dec_ctx = init_cc_decode(ctx->dec_global_setting);
|
||||
if (!dec_ctx)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
list_add_tail( &(dec_ctx->list), &(ctx->dec_ctx_head) );
|
||||
}
|
||||
return dec_ctx;
|
||||
}
|
||||
|
||||
struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo)
|
||||
{
|
||||
struct encoder_ctx *enc_ctx;
|
||||
unsigned int pn = 0;
|
||||
unsigned char in_format = 1;
|
||||
char *extension;
|
||||
|
||||
|
||||
if (ctx->write_format == CCX_OF_NULL)
|
||||
return NULL;
|
||||
|
||||
if(cinfo)
|
||||
{
|
||||
pn = cinfo->program_number;
|
||||
if (cinfo->codec == CCX_CODEC_ISDB_CC)
|
||||
in_format = 3;
|
||||
else if (cinfo->codec == CCX_CODEC_TELETEXT)
|
||||
in_format = 2;
|
||||
else
|
||||
in_format = 1;
|
||||
}
|
||||
list_for_each_entry(enc_ctx, &ctx->enc_ctx_head, list, struct encoder_ctx)
|
||||
{
|
||||
if ( ctx->multiprogram == CCX_FALSE)
|
||||
return enc_ctx;
|
||||
|
||||
if (enc_ctx->program_number == pn)
|
||||
return enc_ctx;
|
||||
}
|
||||
|
||||
extension = get_file_extension(ccx_options.enc_cfg.write_format);
|
||||
if(!extension)
|
||||
return NULL;
|
||||
|
||||
if(ctx->multiprogram == CCX_FALSE)
|
||||
{
|
||||
if(ctx->out_interval != -1)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(ctx->basefilename) + 10 + strlen(extension);
|
||||
|
||||
freep(&ccx_options.enc_cfg.output_filename);
|
||||
ccx_options.enc_cfg.output_filename = malloc(len);
|
||||
|
||||
sprintf(ccx_options.enc_cfg.output_filename, "%s_%06d%s", ctx->basefilename, ctx->segment_counter+1, extension);
|
||||
}
|
||||
if (list_empty(&ctx->enc_ctx_head))
|
||||
{
|
||||
ccx_options.enc_cfg.program_number = pn;
|
||||
ccx_options.enc_cfg.in_format = in_format;
|
||||
enc_ctx = init_encoder(&ccx_options.enc_cfg);
|
||||
if (!enc_ctx)
|
||||
return NULL;
|
||||
list_add_tail( &(enc_ctx->list), &(ctx->enc_ctx_head) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(ctx->basefilename) + 10 + strlen(extension);
|
||||
|
||||
ccx_options.enc_cfg.program_number = pn;
|
||||
ccx_options.enc_cfg.output_filename = malloc(len);
|
||||
if (!ccx_options.enc_cfg.output_filename)
|
||||
{
|
||||
freep(&extension);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(ccx_options.enc_cfg.output_filename, "%s_%d%s", ctx->basefilename, pn, extension);
|
||||
enc_ctx = init_encoder(&ccx_options.enc_cfg);
|
||||
if (!enc_ctx)
|
||||
{
|
||||
freep(&extension);
|
||||
freep(&ccx_options.enc_cfg.output_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_add_tail( &(enc_ctx->list), &(ctx->enc_ctx_head) );
|
||||
freep(&extension);
|
||||
freep(&ccx_options.enc_cfg.output_filename);
|
||||
}
|
||||
freep(&extension);
|
||||
return enc_ctx;
|
||||
}
|
||||
|
||||
struct encoder_ctx *update_encoder_list(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
return update_encoder_list_cinfo(ctx, NULL);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CCX_CCEXTRACTOR_H
|
||||
#define CCX_CCEXTRACTOR_H
|
||||
|
||||
#define VERSION "0.77"
|
||||
#define VERSION "0.78"
|
||||
|
||||
// Load common includes and constants for library usage
|
||||
#include "ccx_common_platform.h"
|
||||
@@ -12,111 +12,33 @@
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
#include "ccx_demuxer.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_decoders_xds.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "bitstream.h"
|
||||
|
||||
#include "networking.h"
|
||||
|
||||
extern int cc_buffer_saved; // Do we have anything in the CC buffer already?
|
||||
extern int ccblocks_in_avc_total; // Total CC blocks found by the AVC code
|
||||
extern int ccblocks_in_avc_lost; // CC blocks found by the AVC code lost due to overwrites (should be 0)
|
||||
|
||||
#define TS_PMT_MAP_SIZE 128
|
||||
|
||||
struct ts_payload
|
||||
{
|
||||
unsigned char *start; // Payload start
|
||||
unsigned length; // Payload length
|
||||
unsigned pesstart; // PES or PSI start
|
||||
unsigned pid; // Stream PID
|
||||
int counter; // continuity counter
|
||||
int transport_error; // 0 = packet OK, non-zero damaged
|
||||
unsigned char section_buf[1024];
|
||||
int section_index;
|
||||
int section_size;
|
||||
};
|
||||
|
||||
struct PAT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned char *last_pmt_payload;
|
||||
unsigned last_pmt_length;
|
||||
};
|
||||
|
||||
struct PMT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned elementary_PID;
|
||||
unsigned ccx_stream_type;
|
||||
unsigned printable_stream_type;
|
||||
};
|
||||
|
||||
struct EIT_buffer
|
||||
{
|
||||
uint32_t prev_ccounter;
|
||||
uint8_t *buffer;
|
||||
uint32_t buffer_length;
|
||||
uint32_t ccounter;
|
||||
};
|
||||
|
||||
struct EPG_rating
|
||||
{
|
||||
char country_code[4];
|
||||
uint8_t age;
|
||||
};
|
||||
|
||||
struct EPG_event
|
||||
{
|
||||
uint32_t id;
|
||||
char start_time_string[21]; //"YYYYMMDDHHMMSS +0000" = 20 chars
|
||||
char end_time_string[21];
|
||||
uint8_t running_status;
|
||||
uint8_t free_ca_mode;
|
||||
char ISO_639_language_code[4];
|
||||
char *event_name;
|
||||
char *text;
|
||||
char extended_ISO_639_language_code[4];
|
||||
char *extended_text;
|
||||
uint8_t has_simple;
|
||||
struct EPG_rating *ratings;
|
||||
uint32_t num_ratings;
|
||||
uint8_t *categories;
|
||||
uint32_t num_categories;
|
||||
uint16_t service_id;
|
||||
long long int count; //incremented by one each time the event is updated
|
||||
uint8_t live_output; //boolean flag, true if this event has been output
|
||||
};
|
||||
|
||||
#define EPG_MAX_EVENTS 60*24*7
|
||||
struct EIT_program
|
||||
{
|
||||
uint32_t array_len;
|
||||
struct EPG_event epg_events[EPG_MAX_EVENTS];
|
||||
};
|
||||
#include "avc_functions.h"
|
||||
//#include "ccx_decoders_708.h"
|
||||
|
||||
/* Report information */
|
||||
#define SUB_STREAMS_CNT 10
|
||||
|
||||
#define TELETEXT_CHUNK_LEN 1 + 8 + 44
|
||||
struct file_report
|
||||
{
|
||||
unsigned program_cnt;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned aspect_ratio;
|
||||
unsigned frame_rate;
|
||||
struct ccx_decoder_608_report *data_from_608;
|
||||
struct ccx_decoder_708_report_t *data_from_708;
|
||||
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
|
||||
struct ccx_decoder_dtvcc_report *data_from_708;
|
||||
unsigned mp4_cc_track_cnt;
|
||||
};
|
||||
|
||||
// Stuff for telcc.c
|
||||
struct ccx_s_teletext_config {
|
||||
struct ccx_s_teletext_config
|
||||
{
|
||||
uint8_t verbose : 1; // should telxcc be verbose?
|
||||
uint16_t page; // teletext page containing cc we want to filter
|
||||
uint16_t tid; // 13-bit packet ID for teletext stream
|
||||
@@ -126,7 +48,6 @@ struct ccx_s_teletext_config {
|
||||
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
|
||||
// uint64_t utc_refvalue; // UTC referential value => Moved to ccx_decoders_common, so can be used for other decoders (608/xds) too
|
||||
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
|
||||
ccx_encoders_transcript_format *transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
@@ -138,18 +59,16 @@ struct ccx_s_teletext_config {
|
||||
int nofontcolor;
|
||||
char millis_separator;
|
||||
};
|
||||
#define MAX_PID 65536
|
||||
|
||||
struct ccx_s_mp4Cfg
|
||||
{
|
||||
unsigned int mp4vidtrack :1;
|
||||
};
|
||||
|
||||
struct lib_ccx_ctx
|
||||
{
|
||||
// TODO relates to fts_global
|
||||
uint32_t global_timestamp;
|
||||
uint32_t min_global_timestamp;
|
||||
int global_timestamp_inited;
|
||||
|
||||
|
||||
// Stuff common to both loops
|
||||
unsigned char *buffer;
|
||||
LLONG past; /* Position in file, if in sync same as ftell() */
|
||||
unsigned char *pesheaderbuf;
|
||||
LLONG inputsize;
|
||||
LLONG total_inputsize;
|
||||
@@ -157,10 +76,6 @@ struct lib_ccx_ctx
|
||||
|
||||
int last_reported_progress;
|
||||
|
||||
// Small buffer to help us with the initial sync
|
||||
unsigned char startbytes[STARTBYTESLENGTH];
|
||||
unsigned int startbytes_pos;
|
||||
int startbytes_avail;
|
||||
|
||||
/* Stats */
|
||||
int stat_numuserheaders;
|
||||
@@ -171,26 +86,11 @@ struct lib_ccx_ctx
|
||||
int stat_dishheaders;
|
||||
int stat_hdtv;
|
||||
int stat_divicom;
|
||||
unsigned total_pulldownfields;
|
||||
unsigned total_pulldownframes;
|
||||
int false_pict_header;
|
||||
|
||||
/* GOP-based timing */
|
||||
int saw_gop_header;
|
||||
int frames_since_last_gop;
|
||||
|
||||
|
||||
/* Time info for timed-transcript */
|
||||
int max_gop_length; // (Maximum) length of a group of pictures
|
||||
int last_gop_length; // Length of the previous group of pictures
|
||||
|
||||
// int hex_mode=HEX_NONE; // Are we processing an hex file?
|
||||
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
enum ccx_stream_mode_enum stream_mode;
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
int m2ts;
|
||||
|
||||
struct ccx_decoders_common_settings_t *dec_global_setting;
|
||||
struct list_head dec_ctx_head;
|
||||
|
||||
int rawmode; // Broadcast or DVD
|
||||
// See -d from
|
||||
@@ -212,22 +112,9 @@ struct lib_ccx_ctx
|
||||
char **inputfile; // List of files to process
|
||||
int num_input_files; // How many?
|
||||
|
||||
/* Hauppauge support */
|
||||
unsigned hauppauge_warning_shown; // Did we detect a possible Hauppauge capture and told the user already?
|
||||
unsigned teletext_warning_shown; // Did we detect a possible PAL (with teletext subs) and told the user already?
|
||||
|
||||
// Output structures
|
||||
struct ccx_s_write wbout1;
|
||||
struct ccx_s_write wbout2;
|
||||
|
||||
/* File handles */
|
||||
FILE *fh_out_elementarystream;
|
||||
int infd; // descriptor number to input.
|
||||
int PIDs_seen[MAX_PID];
|
||||
struct PMT_entry *PIDs_programs[MAX_PID];
|
||||
|
||||
//struct EIT_buffer eit_buffer;
|
||||
struct EIT_buffer epg_buffers[0xfff+1];
|
||||
struct PSI_buffer epg_buffers[0xfff+1];
|
||||
struct EIT_program eit_programs[TS_PMT_MAP_SIZE+1];
|
||||
int32_t eit_current_events[TS_PMT_MAP_SIZE+1];
|
||||
int16_t ATSC_source_pg_map[0xffff];
|
||||
@@ -235,47 +122,22 @@ struct lib_ccx_ctx
|
||||
int epg_last_live_output;
|
||||
struct file_report freport;
|
||||
|
||||
long capbufsize;
|
||||
unsigned char *capbuf;
|
||||
long capbuflen; // Bytes read in capbuf
|
||||
|
||||
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
unsigned int hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
|
||||
0 -> A regular file
|
||||
>0 -> Live stream with a timeout of this value in seconds */
|
||||
int binary_concat; // Disabled by -ve or --videoedited
|
||||
int multiprogram;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
|
||||
struct ccx_demuxer *demux_ctx;
|
||||
struct list_head enc_ctx_head;
|
||||
struct ccx_s_mp4Cfg mp4_cfg;
|
||||
int out_interval;
|
||||
int segment_counter;
|
||||
LLONG system_start_time;
|
||||
};
|
||||
#ifdef DEBUG_TELEXCC
|
||||
int main_telxcc (int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#define buffered_skip(ctx, bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else result=buffered_read_opt (ctx, NULL,bytes);
|
||||
|
||||
#define buffered_read(ctx, buffer,bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer!=NULL) memcpy (buffer,filebuffer+filebuffer_pos,bytes); \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else { result=buffered_read_opt (ctx, buffer,bytes); if (ccx_options.gui_mode_reports && ccx_options.input_source==CCX_DS_NETWORK) {net_activity_gui++; if (!(net_activity_gui%1000))activity_report_data_read();}}
|
||||
|
||||
#define buffered_read_4(buffer) if (4<=bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { buffer[0]=filebuffer[filebuffer_pos]; \
|
||||
buffer[1]=filebuffer[filebuffer_pos+1]; \
|
||||
buffer[2]=filebuffer[filebuffer_pos+2]; \
|
||||
buffer[3]=filebuffer[filebuffer_pos+3]; \
|
||||
filebuffer_pos+=4; \
|
||||
result=4; } \
|
||||
} else result=buffered_read_opt (buffer,4);
|
||||
|
||||
#define buffered_read_byte(ctx, buffer) if (bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
|
||||
filebuffer_pos++; \
|
||||
result=1; } \
|
||||
} else result=buffered_read_opt (ctx, buffer,1);
|
||||
|
||||
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt);
|
||||
void dinit_libraries( struct lib_ccx_ctx **ctx);
|
||||
@@ -288,51 +150,31 @@ int atoi_hex (char *s);
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt);
|
||||
|
||||
// general_loop.c
|
||||
void position_sanity_check (void);
|
||||
int init_file_buffer( void );
|
||||
LLONG ps_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
LLONG general_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
void raw_loop (struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
LLONG process_raw (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
|
||||
void general_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
void position_sanity_check (int in);
|
||||
int init_file_buffer(struct ccx_demuxer *ctx);
|
||||
int ps_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
|
||||
int general_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **data);
|
||||
void raw_loop (struct lib_ccx_ctx *ctx);
|
||||
size_t process_raw(struct lib_cc_decode *ctx, struct cc_subtitle *sub, unsigned char *buffer, size_t len);
|
||||
void general_loop(struct lib_ccx_ctx *ctx);
|
||||
void processhex (char *filename);
|
||||
void rcwt_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
void rcwt_loop(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// activity.c
|
||||
void activity_header (void);
|
||||
void activity_progress (int percentaje, int cur_min, int cur_sec);
|
||||
void activity_report_version (void);
|
||||
void activity_input_file_closed (void);
|
||||
void activity_input_file_open (const char *filename);
|
||||
void activity_message (const char *fmt, ...);
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate);
|
||||
void activity_program_number (unsigned program_number);
|
||||
void activity_library_process(enum ccx_common_logging_gui message_type, ...);
|
||||
void activity_report_data_read (void);
|
||||
|
||||
extern LLONG result;
|
||||
extern int end_of_file;
|
||||
extern LLONG inbuf;
|
||||
extern int ccx_bufferdatatype; // Can be RAW or PES
|
||||
|
||||
// asf_functions.c
|
||||
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
int asf_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
|
||||
|
||||
// wtv_functions.c
|
||||
LLONG wtv_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// avc_functions.c
|
||||
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub);
|
||||
void init_avc(void);
|
||||
int wtv_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
|
||||
|
||||
// es_functions.c
|
||||
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG length,struct cc_subtitle *sub);
|
||||
size_t process_m2v(struct lib_cc_decode *ctx, unsigned char *data, size_t length, struct cc_subtitle *sub);
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
// es_userdata.c
|
||||
int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
|
||||
int user_data(struct lib_cc_decode *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
|
||||
|
||||
// bitstream.c - see bitstream.h
|
||||
|
||||
@@ -342,46 +184,47 @@ LLONG gettotalfilessize (struct lib_ccx_ctx *ctx);
|
||||
void prepare_for_new_file (struct lib_ccx_ctx *ctx);
|
||||
void close_input_file (struct lib_ccx_ctx *ctx);
|
||||
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer);
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
|
||||
void return_to_buffer (struct ccx_demuxer *ctx, unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
// sequencing.c
|
||||
void init_hdcc (void);
|
||||
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number,
|
||||
LLONG current_fts_now,struct cc_subtitle *sub);
|
||||
void anchor_hdcc(int seq);
|
||||
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
|
||||
void init_hdcc (struct lib_cc_decode *ctx);
|
||||
void store_hdcc(struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now, struct cc_subtitle *sub);
|
||||
void anchor_hdcc(struct lib_cc_decode *ctx, int seq);
|
||||
void process_hdcc (struct lib_cc_decode *ctx, struct cc_subtitle *sub);
|
||||
|
||||
// params_dump.c
|
||||
void params_dump(struct lib_ccx_ctx *ctx);
|
||||
void print_file_report(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// output.c
|
||||
void init_write(struct ccx_s_write *wb, char *filename);
|
||||
void dinit_write(struct ccx_s_write *wb);
|
||||
int init_write (struct ccx_s_write *wb,char *filename);
|
||||
int writeraw (const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
|
||||
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile);
|
||||
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data, struct cc_subtitle *sub);
|
||||
|
||||
// stream_functions.c
|
||||
int isValidMP4Box(unsigned char *buffer, long position, long *nextBoxLocation, int *boxScore);
|
||||
void detect_stream_type (struct lib_ccx_ctx *ctx);
|
||||
int detect_myth( struct lib_ccx_ctx *ctx );
|
||||
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen);
|
||||
int read_pts_pes(unsigned char*header, int len);
|
||||
void detect_stream_type (struct ccx_demuxer *ctx);
|
||||
int detect_myth( struct ccx_demuxer *ctx );
|
||||
int read_video_pes_header (struct ccx_demuxer *ctx, struct demuxer_data *data, unsigned char *nextheader, int *headerlength, int sbuflen);
|
||||
|
||||
// ts_functions.c
|
||||
void init_ts(struct lib_ccx_ctx *ctx);
|
||||
void dinit_ts (struct lib_ccx_ctx *ctx);
|
||||
int ts_readpacket(struct lib_ccx_ctx* ctx);
|
||||
long ts_readstream(struct lib_ccx_ctx *ctx);
|
||||
LLONG ts_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
int write_section(struct lib_ccx_ctx *ctx, struct ts_payload *payload, unsigned char*buf, int size, int pos);
|
||||
int parse_PMT (struct lib_ccx_ctx *ctx, unsigned char *buf, int len, int pos);
|
||||
int parse_PAT (struct lib_ccx_ctx *ctx);
|
||||
void init_ts(struct ccx_demuxer *ctx);
|
||||
int ts_readpacket(struct ccx_demuxer* ctx, struct ts_payload *payload);
|
||||
long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data);
|
||||
int ts_getmoredata(struct ccx_demuxer *ctx, struct demuxer_data **data);
|
||||
int write_section(struct ccx_demuxer *ctx, struct ts_payload *payload, unsigned char*buf, int size, struct program_info *pinfo);
|
||||
void ts_buffer_psi_packet(struct ccx_demuxer *ctx);
|
||||
int parse_PMT (struct ccx_demuxer *ctx, unsigned char *buf, int len, struct program_info *pinfo);
|
||||
int parse_PAT (struct ccx_demuxer *ctx);
|
||||
void parse_EPG_packet (struct lib_ccx_ctx *ctx);
|
||||
void EPG_free();
|
||||
void EPG_free(struct lib_ccx_ctx *ctx);
|
||||
char* EPG_DVB_decode_string(uint8_t *in, size_t size);
|
||||
void parse_SDT(struct ccx_demuxer *ctx);
|
||||
|
||||
// myth.c
|
||||
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
void myth_loop(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// utility.c
|
||||
void fatal(int exit_code, const char *fmt, ...);
|
||||
@@ -399,91 +242,47 @@ void m_signal(int sig, void (*func)(int));
|
||||
#endif
|
||||
|
||||
|
||||
unsigned encode_line (unsigned char *buffer, unsigned char *text);
|
||||
void buffered_seek (struct lib_ccx_ctx *ctx, int offset);
|
||||
void buffered_seek (struct ccx_demuxer *ctx, int offset);
|
||||
extern void build_parity_table(void);
|
||||
|
||||
void tlt_process_pes_packet(struct lib_ccx_ctx *ctx, uint8_t *buffer, uint16_t size, struct cc_subtitle *sub);
|
||||
void telxcc_init(struct lib_ccx_ctx *ctx);
|
||||
void telxcc_close(struct lib_ccx_ctx *ctx);
|
||||
void tlt_read_rcwt(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
|
||||
int tlt_process_pes_packet(struct lib_cc_decode *dec_ctx, uint8_t *buffer, uint16_t size, struct cc_subtitle *sub);
|
||||
void* telxcc_init(void);
|
||||
void telxcc_close(void **ctx, struct cc_subtitle *sub);
|
||||
void tlt_read_rcwt(void *codec, unsigned char *buf, struct cc_subtitle *sub);
|
||||
void telxcc_configure (void *codec, struct ccx_s_teletext_config *cfg);
|
||||
void telxcc_update_gt(void *codec, uint32_t global_timestamp);
|
||||
|
||||
extern unsigned rollover_bits;
|
||||
extern int global_timestamp_inited;
|
||||
|
||||
extern int strangeheader;
|
||||
|
||||
extern unsigned char *filebuffer;
|
||||
extern LLONG filebuffer_start; // Position of buffer start relative to file
|
||||
extern int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
extern int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
|
||||
extern const char *desc[256];
|
||||
|
||||
|
||||
extern long FILEBUFFERSIZE; // Uppercase because it used to be a define
|
||||
extern unsigned long net_activity_gui;
|
||||
|
||||
/* General (ES stream) video information */
|
||||
extern unsigned current_hor_size;
|
||||
extern unsigned current_vert_size;
|
||||
extern unsigned current_aspect_ratio;
|
||||
extern unsigned current_frame_rate;
|
||||
|
||||
extern enum ccx_bufferdata_type bufferdatatype; // Can be CCX_BUFFERDATA_TYPE_RAW or CCX_BUFFERDATA_TYPE_PES
|
||||
|
||||
extern int firstcall;
|
||||
|
||||
#define MAXBFRAMES 50
|
||||
#define SORTBUF (2*MAXBFRAMES+1)
|
||||
extern int cc_data_count[SORTBUF];
|
||||
extern unsigned char cc_data_pkts[SORTBUF][10*31*3+1];
|
||||
extern int has_ccdata_buffered;
|
||||
|
||||
extern unsigned char *subline;
|
||||
|
||||
|
||||
// From ts_functions
|
||||
extern unsigned cap_stream_type;
|
||||
extern struct ts_payload payload;
|
||||
//extern struct ts_payload payload;
|
||||
extern unsigned char tspacket[188];
|
||||
extern struct PAT_entry pmt_array[TS_PMT_MAP_SIZE];
|
||||
extern uint16_t pmt_array_length;
|
||||
extern unsigned pmtpid;
|
||||
extern unsigned TS_program_number;
|
||||
extern unsigned char *last_pat_payload;
|
||||
extern unsigned last_pat_length;
|
||||
extern long capbuflen;
|
||||
|
||||
|
||||
#define HAUPPAGE_CCPID 1003 // PID for CC's in some Hauppauge recordings
|
||||
|
||||
/* Exit codes. Take this seriously as the GUI depends on them.
|
||||
0 means OK as usual,
|
||||
<100 means display whatever was output to stderr as a warning
|
||||
>=100 means display whatever was output to stdout as an error
|
||||
*/
|
||||
// Some moved to ccx_common_common.h
|
||||
#define EXIT_OK 0
|
||||
#define EXIT_NO_INPUT_FILES 2
|
||||
#define EXIT_TOO_MANY_INPUT_FILES 3
|
||||
#define EXIT_INCOMPATIBLE_PARAMETERS 4
|
||||
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
|
||||
#define EXIT_MALFORMED_PARAMETER 7
|
||||
#define EXIT_READ_ERROR 8
|
||||
#define EXIT_NOT_CLASSIFIED 300
|
||||
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
|
||||
#define EXIT_BUFFER_FULL 502
|
||||
#define EXIT_MISSING_ASF_HEADER 1001
|
||||
#define EXIT_MISSING_RCWT_HEADER 1002
|
||||
|
||||
extern unsigned teletext_mode;
|
||||
|
||||
#define MAX_TLT_PAGES 1000
|
||||
extern short int seen_sub_page[MAX_TLT_PAGES];
|
||||
|
||||
extern struct ccx_s_teletext_config tlt_config;
|
||||
extern uint32_t tlt_packet_counter;
|
||||
extern uint32_t tlt_frames_produced;
|
||||
|
||||
int is_decoder_processed_enough(struct lib_ccx_ctx *ctx);
|
||||
struct lib_cc_decode *update_decoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo);
|
||||
struct lib_cc_decode *update_decoder_list(struct lib_ccx_ctx *ctx);
|
||||
|
||||
struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct cap_info* cinfo);
|
||||
struct encoder_ctx * update_encoder_list(struct lib_ccx_ctx *ctx);
|
||||
struct encoder_ctx *get_encoder_by_pn(struct lib_ccx_ctx *ctx, int pn);
|
||||
#endif
|
||||
|
||||
511
src/lib_ccx/list.h
Normal file
511
src/lib_ccx/list.h
Normal file
@@ -0,0 +1,511 @@
|
||||
/**
|
||||
*
|
||||
* Grabed from linux kernel source code and fix it for user space
|
||||
* program. Of course, this is a GPL licensed header file.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
#include "ccx_common_platform.h"
|
||||
/**
|
||||
* @name from other kernel headers
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Get offset of a member
|
||||
*/
|
||||
|
||||
#ifndef ccx_offsetof
|
||||
#define ccx_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Casts a member of a structure out to the containing structure
|
||||
* @param ptr the pointer to the member.
|
||||
* @param type the type of the container struct this is embedded in.
|
||||
* @param member the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#define container_of(ptr, type, member) ((type *)( (char *)ptr - ccx_offsetof(type,member) ))
|
||||
/*@}*/
|
||||
|
||||
|
||||
/*
|
||||
* These are non-NULL pointers that will result in page faults
|
||||
* under normal circumstances, used to verify that nobody uses
|
||||
* non-initialized list entries.
|
||||
*/
|
||||
#define LIST_POISON1 ((void *) 0x00100100)
|
||||
#define LIST_POISON2 ((void *) 0x00200200)
|
||||
|
||||
/**
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* __list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*
|
||||
* This variant differs from list_for_each() in that it's the
|
||||
* simplest possible list iteration code, no prefetching is done.
|
||||
* Use this for code that knows the list to be very short (empty
|
||||
* or 1 entry) most of the time.
|
||||
*/
|
||||
#define __list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
|
||||
pos = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
* @type iterator type
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member, type) \
|
||||
for (pos = list_entry((head)->next, type, member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, type, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use as a start point in
|
||||
* list_for_each_entry_continue
|
||||
* @pos: the type * to use as a start point
|
||||
* @head: the head of the list
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_prepare_entry(pos, head, member) \
|
||||
((pos) ? : list_entry(head, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - iterate over list of given type
|
||||
* continuing after existing point
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member, type) \
|
||||
for (pos = list_entry((head)->next, type, member), \
|
||||
n = list_entry(pos->member.next, type, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, type, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_continue - iterate over list of given type
|
||||
* continuing after existing point safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
|
||||
* removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Double linked lists with a single pointer list head.
|
||||
* Mostly useful for hash tables where the two pointer list head is
|
||||
* too wasteful.
|
||||
* You lose the ability to access the tail in O(1).
|
||||
*/
|
||||
|
||||
struct hlist_head {
|
||||
struct hlist_node *first;
|
||||
};
|
||||
|
||||
struct hlist_node {
|
||||
struct hlist_node *next, **pprev;
|
||||
};
|
||||
|
||||
#define HLIST_HEAD_INIT { .first = NULL }
|
||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
||||
#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
|
||||
|
||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
||||
{
|
||||
return !h->pprev;
|
||||
}
|
||||
|
||||
static inline int hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
return !h->first;
|
||||
}
|
||||
|
||||
static inline void __hlist_del(struct hlist_node *n)
|
||||
{
|
||||
struct hlist_node *next = n->next;
|
||||
struct hlist_node **pprev = n->pprev;
|
||||
*pprev = next;
|
||||
if (next)
|
||||
next->pprev = pprev;
|
||||
}
|
||||
|
||||
static inline void hlist_del(struct hlist_node *n)
|
||||
{
|
||||
__hlist_del(n);
|
||||
n->next = LIST_POISON1;
|
||||
n->pprev = LIST_POISON2;
|
||||
}
|
||||
|
||||
|
||||
static inline void hlist_del_init(struct hlist_node *n)
|
||||
{
|
||||
if (n->pprev) {
|
||||
__hlist_del(n);
|
||||
INIT_HLIST_NODE(n);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
struct hlist_node *first = h->first;
|
||||
n->next = first;
|
||||
if (first)
|
||||
first->pprev = &n->next;
|
||||
h->first = n;
|
||||
n->pprev = &h->first;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* next must be != NULL */
|
||||
static inline void hlist_add_before(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
n->pprev = next->pprev;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
*(n->pprev) = n;
|
||||
}
|
||||
|
||||
static inline void hlist_add_after(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
next->next = n->next;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
|
||||
if(next->next)
|
||||
next->next->pprev = &next->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
#define hlist_for_each(pos, head) \
|
||||
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
|
||||
pos = pos->next)
|
||||
|
||||
#define hlist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry - iterate over list of given type
|
||||
* @tpos: the type * to use as a loop counter.
|
||||
* @pos: the &struct hlist_node to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry(tpos, pos, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
|
||||
* @tpos: the type * to use as a loop counter.
|
||||
* @pos: the &struct hlist_node to use as a loop counter.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_continue(tpos, pos, member) \
|
||||
for (pos = (pos)->next; \
|
||||
pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_from - iterate over a hlist continuing from existing point
|
||||
* @tpos: the type * to use as a loop counter.
|
||||
* @pos: the &struct hlist_node to use as a loop counter.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_from(tpos, pos, member) \
|
||||
for (; pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @tpos: the type * to use as a loop counter.
|
||||
* @pos: the &struct hlist_node to use as a loop counter.
|
||||
* @n: another &struct hlist_node to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ n = pos->next; 1; }) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = n)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,10 +14,11 @@ For now, integration with ccextractor is a quick hack. It could get better with
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "activity.h"
|
||||
#include "file_buffer.h"
|
||||
|
||||
static unsigned int header_state;
|
||||
static unsigned char psm_es_type[256];
|
||||
int cc608_parity_table[256];
|
||||
|
||||
// LLONG processed_ccblocks = 0;
|
||||
|
||||
@@ -288,61 +289,29 @@ typedef struct AVPacket
|
||||
|
||||
static AVPacket av;
|
||||
|
||||
int get_be16(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned char a,b;
|
||||
unsigned char *a_p = &a; // Just to suppress warnings
|
||||
unsigned char *b_p = &b;
|
||||
buffered_read_byte (ctx, a_p);
|
||||
ctx->past++;
|
||||
buffered_read_byte (ctx, b_p);
|
||||
ctx->past++;
|
||||
return (a<<8) | b;
|
||||
}
|
||||
|
||||
int get_byte (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned char b;
|
||||
unsigned char *b_p = &b;
|
||||
buffered_read_byte(ctx, b_p);
|
||||
if (result==1)
|
||||
{
|
||||
ctx->past++;
|
||||
return b;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_be32(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned int val;
|
||||
val = get_be16(ctx) << 16;
|
||||
val |= get_be16(ctx);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static LLONG get_pts(struct lib_ccx_ctx *ctx, int c)
|
||||
static LLONG get_pts(struct ccx_demuxer *ctx, int c)
|
||||
{
|
||||
LLONG pts;
|
||||
int val;
|
||||
|
||||
if (c < 0)
|
||||
c = get_byte(ctx);
|
||||
c = buffered_get_byte(ctx);
|
||||
pts = (LLONG) ((c >> 1) & 0x07) << 30;
|
||||
val = get_be16(ctx);
|
||||
val = buffered_get_be16(ctx);
|
||||
pts |= (LLONG) (val >> 1) << 15;
|
||||
val = get_be16(ctx);
|
||||
val = buffered_get_be16(ctx);
|
||||
pts |= (LLONG) (val >> 1);
|
||||
return pts;
|
||||
}
|
||||
|
||||
static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
|
||||
static int find_next_start_code(struct ccx_demuxer *ctx, int *size_ptr,
|
||||
unsigned int *header_state)
|
||||
{
|
||||
unsigned int state, v;
|
||||
int val, n;
|
||||
LLONG result;
|
||||
|
||||
state = *header_state;
|
||||
n = *size_ptr;
|
||||
@@ -350,8 +319,8 @@ static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
|
||||
{
|
||||
unsigned char cx;
|
||||
unsigned char *cx_p = &cx;
|
||||
buffered_read_byte (ctx, cx_p);
|
||||
if (result!=1)
|
||||
result = buffered_read_byte(ctx, cx_p);
|
||||
if (result != 1)
|
||||
break;
|
||||
ctx->past++;
|
||||
v = cx;
|
||||
@@ -370,43 +339,43 @@ found:
|
||||
return val;
|
||||
}
|
||||
|
||||
void url_fskip (struct lib_ccx_ctx *ctx, int length)
|
||||
void url_fskip (struct ccx_demuxer *ctx, int length)
|
||||
{
|
||||
buffered_seek (ctx, length);
|
||||
ctx->past+=length;
|
||||
ctx->past += length;
|
||||
}
|
||||
|
||||
static long mpegps_psm_parse(struct lib_ccx_ctx *ctx)
|
||||
static long mpegps_psm_parse(struct ccx_demuxer *ctx)
|
||||
{
|
||||
int psm_length, ps_info_length, es_map_length;
|
||||
|
||||
psm_length = get_be16(ctx);
|
||||
get_byte(ctx);
|
||||
get_byte(ctx);
|
||||
ps_info_length = get_be16(ctx);
|
||||
psm_length = buffered_get_be16(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
ps_info_length = buffered_get_be16(ctx);
|
||||
|
||||
/* skip program_stream_info */
|
||||
url_fskip(ctx, ps_info_length);
|
||||
es_map_length = get_be16(ctx);
|
||||
es_map_length = buffered_get_be16(ctx);
|
||||
|
||||
/* at least one es available? */
|
||||
while (es_map_length >= 4)
|
||||
{
|
||||
unsigned char type = (unsigned char) get_byte(ctx);
|
||||
unsigned char es_id =(unsigned char) get_byte(ctx);
|
||||
unsigned int es_info_length = get_be16(ctx);
|
||||
unsigned char type = (unsigned char) buffered_get_byte(ctx);
|
||||
unsigned char es_id =(unsigned char) buffered_get_byte(ctx);
|
||||
unsigned int es_info_length = buffered_get_be16(ctx);
|
||||
/* remember mapping from stream id to stream type */
|
||||
psm_es_type[es_id] = type;
|
||||
/* skip program_stream_info */
|
||||
url_fskip(ctx, es_info_length);
|
||||
es_map_length -= 4 + es_info_length;
|
||||
}
|
||||
get_be32(ctx); /* crc32 */
|
||||
buffered_get_be32(ctx); /* crc32 */
|
||||
return 2 + psm_length;
|
||||
}
|
||||
|
||||
|
||||
static int mpegps_read_pes_header(struct lib_ccx_ctx *ctx, int *pstart_code,
|
||||
static int mpegps_read_pes_header(struct ccx_demuxer *ctx, int *pstart_code,
|
||||
LLONG *ppts, LLONG *pdts)
|
||||
{
|
||||
int len, size, startcode, c, flags, header_len;
|
||||
@@ -428,11 +397,11 @@ redo:
|
||||
startcode == PRIVATE_STREAM_2)
|
||||
{
|
||||
/* skip them */
|
||||
len = get_be16(ctx);
|
||||
len = buffered_get_be16(ctx);
|
||||
// url_fskip(ctx, len);
|
||||
goto redo;
|
||||
}
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
if (startcode == PROGRAM_STREAM_MAP)
|
||||
{
|
||||
mpegps_psm_parse(ctx);
|
||||
@@ -445,30 +414,30 @@ redo:
|
||||
(startcode == 0x1bd)))
|
||||
goto redo;
|
||||
|
||||
len = get_be16(ctx);
|
||||
len = buffered_get_be16(ctx);
|
||||
pts = AV_NOPTS_VALUE;
|
||||
dts = AV_NOPTS_VALUE;
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
/* stuffing */
|
||||
for(;;) {
|
||||
if (len < 1)
|
||||
goto redo;
|
||||
c = get_byte(ctx);
|
||||
c = buffered_get_byte(ctx);
|
||||
len--;
|
||||
/* XXX: for mpeg1, should test only bit 7 */
|
||||
if (c != 0xff)
|
||||
break;
|
||||
}
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
if ((c & 0xc0) == 0x40) {
|
||||
/* buffer scale & size */
|
||||
if (len < 2)
|
||||
goto redo;
|
||||
get_byte(ctx);
|
||||
c = get_byte(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
c = buffered_get_byte(ctx);
|
||||
len -= 2;
|
||||
}
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
if ((c & 0xf0) == 0x20) {
|
||||
if (len < 4)
|
||||
goto redo;
|
||||
@@ -488,8 +457,8 @@ redo:
|
||||
goto redo;
|
||||
}
|
||||
#endif
|
||||
flags = get_byte(ctx);
|
||||
header_len = get_byte(ctx);
|
||||
flags = buffered_get_byte(ctx);
|
||||
header_len = buffered_get_byte(ctx);
|
||||
len -= 2;
|
||||
if (header_len > len)
|
||||
goto redo;
|
||||
@@ -509,26 +478,26 @@ redo:
|
||||
}
|
||||
len -= header_len;
|
||||
while (header_len > 0) {
|
||||
get_byte(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
header_len--;
|
||||
}
|
||||
}
|
||||
else if( c!= 0xf )
|
||||
goto redo;
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
if (startcode == PRIVATE_STREAM_1 /* && psm_es_type[startcode & 0xff] */)
|
||||
{
|
||||
if (len < 1)
|
||||
goto redo;
|
||||
startcode = get_byte(ctx);
|
||||
startcode = buffered_get_byte(ctx);
|
||||
len--;
|
||||
if (startcode >= 0x80 && startcode <= 0xbf) {
|
||||
/* audio: skip header */
|
||||
if (len < 3)
|
||||
goto redo;
|
||||
get_byte(ctx);
|
||||
get_byte(ctx);
|
||||
get_byte(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
buffered_get_byte(ctx);
|
||||
len -= 3;
|
||||
}
|
||||
}
|
||||
@@ -563,7 +532,7 @@ void ProcessVBIDataPacket(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
}
|
||||
|
||||
LLONG linemask = 0;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
// unsigned long long utc = lastccptsu;
|
||||
|
||||
// [i]tv0 means there is a linemask
|
||||
@@ -646,7 +615,7 @@ void ProcessVBIDataPacket(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
// lastccptsu = utc;
|
||||
}
|
||||
|
||||
static int mpegps_read_packet(struct lib_ccx_ctx *ctx)
|
||||
static int mpegps_read_packet(struct ccx_demuxer *ctx)
|
||||
{
|
||||
LLONG pts, dts;
|
||||
|
||||
@@ -655,7 +624,7 @@ redo:
|
||||
len = mpegps_read_pes_header(ctx, &startcode, &pts, &dts);
|
||||
if (len < 0)
|
||||
return len;
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->infd);
|
||||
/* now find stream */
|
||||
/*
|
||||
for(i=0;i<s->nb_streams;i++) {
|
||||
@@ -697,7 +666,7 @@ redo:
|
||||
{
|
||||
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
|
||||
unsigned char buf[8];
|
||||
buffered_read (ctx, buf,8);
|
||||
buffered_read(ctx, buf, 8);
|
||||
ctx->past+=8;
|
||||
// get_buffer(&s->pb, buf, 8);
|
||||
buffered_seek(ctx, -8);
|
||||
@@ -755,9 +724,9 @@ goto skip; */
|
||||
// audio data
|
||||
if (len <= 3)
|
||||
goto skip;
|
||||
get_byte(ctx); // emphasis (1), muse(1), reserved(1), frame number(5)
|
||||
get_byte(ctx); // quant (2), freq(2), reserved(1), channels(3)
|
||||
get_byte(ctx); // dynamic range control (0x80 = off)
|
||||
buffered_get_byte(ctx); // emphasis (1), muse(1), reserved(1), frame number(5)
|
||||
buffered_get_byte(ctx); // quant (2), freq(2), reserved(1), channels(3)
|
||||
buffered_get_byte(ctx); // dynamic range control (0x80 = off)
|
||||
len -= 3;
|
||||
//freq = (b1 >> 4) & 3;
|
||||
//st->codec->sample_rate = lpcm_freq_tab[freq];
|
||||
@@ -779,9 +748,9 @@ goto skip; */
|
||||
}
|
||||
av.codec_id=codec_id;
|
||||
av.type=type;
|
||||
buffered_read (ctx, av.data,av.size);
|
||||
ctx->past+=av.size;
|
||||
position_sanity_check();
|
||||
buffered_read(ctx, av.data, av.size);
|
||||
ctx->past += av.size;
|
||||
position_sanity_check(ctx->infd);
|
||||
// LSEEK (fh,pkt->size,SEEK_CUR);
|
||||
av.pts = pts;
|
||||
av.dts = dts;
|
||||
@@ -795,62 +764,30 @@ goto skip; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cc608_parity(unsigned int byte)
|
||||
{
|
||||
int ones = 0;
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
if (byte & (1 << i))
|
||||
ones++;
|
||||
}
|
||||
|
||||
return ones & 1;
|
||||
}
|
||||
|
||||
static void cc608_build_parity_table(int *parity_table)
|
||||
{
|
||||
unsigned int byte;
|
||||
int parity_v;
|
||||
for (byte = 0; byte <= 127; byte++)
|
||||
{
|
||||
parity_v = cc608_parity(byte);
|
||||
/* CC uses odd parity (i.e., # of 1's in byte is odd.) */
|
||||
parity_table[byte] = parity_v;
|
||||
parity_table[byte | 0x80] = !parity_v;
|
||||
}
|
||||
}
|
||||
|
||||
void build_parity_table (void)
|
||||
{
|
||||
cc608_build_parity_table(cc608_parity_table);
|
||||
}
|
||||
|
||||
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
void myth_loop(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int rc;
|
||||
int has_vbi=0;
|
||||
LLONG saved = 0;
|
||||
struct cc_subtitle dec_sub;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
|
||||
unsigned long desp_length=65536;
|
||||
unsigned char *desp=(unsigned char *) malloc (desp_length);
|
||||
|
||||
av.data=NULL;
|
||||
ccx_options.buffer_input = 1;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
if (init_file_buffer())
|
||||
{
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
|
||||
}
|
||||
unsigned long desp_length=65536;
|
||||
unsigned char *desp=(unsigned char *) malloc (desp_length);
|
||||
dec_ctx = update_decoder_list(ctx);
|
||||
desp_length = 65536;
|
||||
desp = (unsigned char *) malloc (desp_length);
|
||||
if (!desp)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
|
||||
saved=0;
|
||||
|
||||
memset(&dec_sub, 0, sizeof(dec_sub));
|
||||
while (!dec_ctx->processed_enough && (rc=mpegps_read_packet(ctx))==0)
|
||||
while (is_decoder_processed_enough(ctx) == CCX_FALSE && (rc=mpegps_read_packet(ctx->demux_ctx))==0)
|
||||
{
|
||||
position_sanity_check();
|
||||
position_sanity_check(ctx->demux_ctx->infd);
|
||||
if (av.codec_id==CODEC_ID_MPEG2VBI && av.type==CODEC_TYPE_DATA)
|
||||
{
|
||||
if (!has_vbi)
|
||||
@@ -874,19 +811,17 @@ void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
}
|
||||
if (av.pts!=AV_NOPTS_VALUE)
|
||||
{
|
||||
current_pts=av.pts;
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_current_pts(dec_ctx->timing, av.pts);
|
||||
}
|
||||
memcpy (desp+saved,av.data,av.size);
|
||||
LLONG used = process_m2v(ctx, desp, length, &dec_sub);
|
||||
LLONG used = process_m2v(dec_ctx, desp, length, &dec_sub);
|
||||
memmove (desp,desp+used,(unsigned int) (length-used));
|
||||
saved=length-used;
|
||||
}
|
||||
|
||||
if (ccx_options.live_stream)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
int th=cur_sec/10;
|
||||
if (ctx->last_reported_progress!=th)
|
||||
{
|
||||
@@ -898,10 +833,10 @@ void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
{
|
||||
if (ctx->total_inputsize > 0 )
|
||||
{
|
||||
int progress = (int) ((((ctx->total_past+ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
|
||||
int progress = (int) ((((ctx->total_past+ctx->demux_ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
|
||||
activity_progress (progress, cur_sec/60, cur_sec%60);
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
@@ -16,30 +16,39 @@
|
||||
#define PASSWORD 2
|
||||
#define BIN_MODE 3
|
||||
#define CC_DESC 4
|
||||
#define BIN_HEADER 5
|
||||
#define BIN_DATA 6
|
||||
#define EPG_DATA 7
|
||||
#pragma warning( suppress : 4005)
|
||||
#define ERROR 51
|
||||
#define UNKNOWN_COMMAND 52
|
||||
#define WRONG_PASSWORD 53
|
||||
#define CONN_LIMIT 54
|
||||
#define PING 55
|
||||
|
||||
/* #include <time.h> */
|
||||
|
||||
#define DFT_PORT "2048" /* Default port for server and client */
|
||||
#define WRONG_PASSWORD_DELAY 2 /* Seconds */
|
||||
#define BUFFER_SIZE 50
|
||||
#define NO_RESPONCE_INTERVAL 20
|
||||
#define PING_INTERVAL 3
|
||||
|
||||
int srv_sd = -1; /* Server socket descriptor */
|
||||
|
||||
const char *srv_addr;
|
||||
const char *srv_port;
|
||||
const char *srv_cc_desc;
|
||||
const char *srv_pwd;
|
||||
unsigned char *srv_header;
|
||||
size_t srv_header_len;
|
||||
|
||||
/*
|
||||
* Established connection to speciefied addres.
|
||||
* Returns socked id
|
||||
*/
|
||||
int tcp_connect(const char *addr, const char *port);
|
||||
|
||||
/*
|
||||
* Asks password from stdin, sends it to the server and waits for
|
||||
* it's response
|
||||
*/
|
||||
int ask_passwd(int sd);
|
||||
|
||||
int check_password(int fd, const char *pwd);
|
||||
|
||||
int tcp_bind(const char *port, int *family);
|
||||
@@ -68,7 +77,10 @@ void init_sockets (void);
|
||||
void pr_command(char c);
|
||||
#endif
|
||||
|
||||
void connect_to_srv(const char *addr, const char *port, const char *cc_desc)
|
||||
void handle_write_error();
|
||||
int set_nonblocking(int fd);
|
||||
|
||||
void connect_to_srv(const char *addr, const char *port, const char *cc_desc, const char *pwd)
|
||||
{
|
||||
if (NULL == addr)
|
||||
{
|
||||
@@ -85,14 +97,16 @@ void connect_to_srv(const char *addr, const char *port, const char *cc_desc)
|
||||
if ((srv_sd = tcp_connect(addr, port)) < 0)
|
||||
fatal(EXIT_FAILURE, "Unable to connect\n");
|
||||
|
||||
if (ask_passwd(srv_sd) < 0)
|
||||
if (write_block(srv_sd, PASSWORD, pwd, pwd ? strlen(pwd) : 0) < 0)
|
||||
fatal(EXIT_FAILURE, "Unable to connect\n");
|
||||
|
||||
if (cc_desc != NULL &&
|
||||
write_block(srv_sd, CC_DESC, cc_desc, strlen(cc_desc)) < 0)
|
||||
{
|
||||
if (write_block(srv_sd, CC_DESC, cc_desc, cc_desc ? strlen(cc_desc) : 0) < 0)
|
||||
fatal(EXIT_FAILURE, "Unable to connect\n");
|
||||
}
|
||||
|
||||
srv_addr = addr;
|
||||
srv_port = port;
|
||||
srv_cc_desc = cc_desc;
|
||||
srv_pwd = pwd;
|
||||
|
||||
mprint("Connected to %s:%s\n", addr, port);
|
||||
}
|
||||
@@ -106,35 +120,21 @@ void net_send_header(const unsigned char *data, size_t len)
|
||||
fprintf(stderr, "File created by %02X version %02X%02X\n", data[3], data[4], data[5]);
|
||||
fprintf(stderr, "File format revision: %02X%02X\n", data[6], data[7]);
|
||||
#endif
|
||||
if (write_block(srv_sd, BIN_MODE, NULL, 0) <= 0)
|
||||
|
||||
if (write_block(srv_sd, BIN_HEADER, data, len) <= 0)
|
||||
{
|
||||
printf("Can't send BIN header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char ok;
|
||||
if (read_byte(srv_sd, &ok) != 1)
|
||||
if (srv_header != NULL)
|
||||
return;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] ");
|
||||
pr_command(ok);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if ((srv_header = malloc(len)) == NULL)
|
||||
fatal(EXIT_FAILURE, "Not enought memory");
|
||||
|
||||
if (ERROR == ok)
|
||||
{
|
||||
printf("Internal server error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t rc;
|
||||
if ((rc = writen(srv_sd, data, len)) != (int) len)
|
||||
{
|
||||
if (rc < 0)
|
||||
mprint("write() error: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
memcpy(srv_header, data, len);
|
||||
srv_header_len = len;
|
||||
}
|
||||
|
||||
int net_send_cc(const unsigned char *data, int len, void *private_data, struct cc_subtitle *sub)
|
||||
@@ -145,17 +145,186 @@ int net_send_cc(const unsigned char *data, int len, void *private_data, struct c
|
||||
fprintf(stderr, "[C] Sending %u bytes\n", len);
|
||||
#endif
|
||||
|
||||
ssize_t rc;
|
||||
if ((rc = writen(srv_sd, data, len)) != (int) len)
|
||||
if (write_block(srv_sd, BIN_DATA, data, len) <= 0)
|
||||
{
|
||||
if (rc < 0)
|
||||
mprint("write() error: %s", strerror(errno));
|
||||
return rc;
|
||||
printf("Can't send BIN data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
|
||||
/* nanosleep((struct timespec[]){{0, 4000000}}, NULL); */
|
||||
/* Sleep(100); */
|
||||
return rc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void net_check_conn()
|
||||
{
|
||||
time_t now;
|
||||
static time_t last_ping = 0;
|
||||
char c = 0;
|
||||
int rc;
|
||||
|
||||
if (srv_sd <= 0)
|
||||
return;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
if (last_ping == 0)
|
||||
last_ping = now;
|
||||
|
||||
do {
|
||||
c = 0;
|
||||
rc = read_byte(srv_sd, &c);
|
||||
if (c == PING) {
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] Recieved PING\n");
|
||||
#endif
|
||||
last_ping = now;
|
||||
}
|
||||
} while (rc > 0 && c == PING);
|
||||
|
||||
if (now - last_ping > NO_RESPONCE_INTERVAL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[S] No PING recieved from the server in %u sec, reconnecting\n",
|
||||
NO_RESPONCE_INTERVAL);
|
||||
close(srv_sd);
|
||||
srv_sd = -1;
|
||||
|
||||
connect_to_srv(srv_addr, srv_port, srv_cc_desc, srv_pwd);
|
||||
|
||||
net_send_header(srv_header, srv_header_len);
|
||||
last_ping = now;
|
||||
}
|
||||
|
||||
static time_t last_send_ping = 0;
|
||||
if (now - last_send_ping >= PING_INTERVAL)
|
||||
{
|
||||
if (write_block(srv_sd, PING, NULL, 0) < 0)
|
||||
{
|
||||
printf("Unable to send data\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
last_send_ping = now;
|
||||
}
|
||||
}
|
||||
|
||||
void net_send_epg(
|
||||
const char *start,
|
||||
const char *stop,
|
||||
const char *title,
|
||||
const char *desc,
|
||||
const char *lang,
|
||||
const char *category
|
||||
)
|
||||
{
|
||||
size_t st;
|
||||
size_t sp;
|
||||
size_t t;
|
||||
size_t d;
|
||||
size_t l;
|
||||
size_t c;
|
||||
size_t len;
|
||||
char *epg;
|
||||
char *end;
|
||||
|
||||
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
|
||||
assert(srv_sd > 0);
|
||||
if (NULL == start)
|
||||
return;
|
||||
if (NULL == stop)
|
||||
return;
|
||||
|
||||
st = strlen(start) + 1;
|
||||
sp = strlen(stop) + 1;
|
||||
|
||||
t = 1;
|
||||
if (title != NULL)
|
||||
t += strlen(title);
|
||||
|
||||
d = 1;
|
||||
if (desc != NULL)
|
||||
d += strlen(desc);
|
||||
|
||||
l = 1;
|
||||
if (lang != NULL)
|
||||
l += strlen(lang);
|
||||
|
||||
c = 1;
|
||||
if (category != NULL)
|
||||
c += strlen(category);
|
||||
|
||||
len = st + sp + t + d + l + c;
|
||||
|
||||
epg = (char *) calloc(len, sizeof(char));
|
||||
if (NULL == epg)
|
||||
return;
|
||||
|
||||
end = epg;
|
||||
|
||||
memcpy(end, start, st);
|
||||
end += st;
|
||||
|
||||
memcpy(end, stop, sp);
|
||||
end += sp;
|
||||
|
||||
if (title != NULL)
|
||||
memcpy(end, title, t);
|
||||
end += t;
|
||||
|
||||
if (desc != NULL)
|
||||
memcpy(end, desc, d);
|
||||
end += d;
|
||||
|
||||
if (lang != NULL)
|
||||
memcpy(end, lang, l);
|
||||
end += l;
|
||||
|
||||
if (category != NULL)
|
||||
memcpy(end, category, c);
|
||||
end += c;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[C] Sending EPG: %u bytes\n", len);
|
||||
#endif
|
||||
|
||||
if (write_block(srv_sd, EPG_DATA, epg, len) <= 0)
|
||||
fprintf(stderr, "Can't send EPG data\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int net_tcp_read(int socket, void *buffer, size_t length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0);
|
||||
|
||||
time_t now = time(NULL);
|
||||
static time_t last_ping = 0;
|
||||
if (last_ping == 0)
|
||||
last_ping = now;
|
||||
|
||||
if (now - last_ping > PING_INTERVAL)
|
||||
{
|
||||
last_ping = now;
|
||||
if (write_byte(socket, PING) <= 0)
|
||||
fatal(EXIT_FAILURE, "Unable to send keep-alive packet to client\n");
|
||||
}
|
||||
|
||||
int rc;
|
||||
char c;
|
||||
size_t l;
|
||||
|
||||
do
|
||||
{
|
||||
l = length;
|
||||
|
||||
if ((rc = read_block(socket, &c, buffer, &l)) <= 0)
|
||||
return rc;
|
||||
}
|
||||
while (c != BIN_DATA && c != BIN_HEADER);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,7 +375,7 @@ ssize_t write_block(int fd, char command, const char *buf, size_t buf_len)
|
||||
}
|
||||
|
||||
#if DEBUG_OUT
|
||||
if (buf != NULL)
|
||||
if (buf != NULL && command != BIN_HEADER && command != BIN_DATA)
|
||||
{
|
||||
fwrite(buf, sizeof(char), buf_len, stderr);
|
||||
fprintf(stderr, " ");
|
||||
@@ -296,83 +465,12 @@ int tcp_connect(const char *host, const char *port)
|
||||
if (NULL == p)
|
||||
return -1;
|
||||
|
||||
if (set_nonblocking(sockfd) < 0)
|
||||
return -1;
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
int ask_passwd(int sd)
|
||||
{
|
||||
assert(sd >= 0);
|
||||
|
||||
size_t len;
|
||||
char pw[BUFFER_SIZE] = { 0 };
|
||||
|
||||
char ok;
|
||||
|
||||
do {
|
||||
do {
|
||||
if (read_byte(sd, &ok) != 1)
|
||||
{
|
||||
fatal(EXIT_FAILURE, "read() error: %s", strerror(errno));
|
||||
}
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] ");
|
||||
pr_command(ok);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
if (OK == ok)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (CONN_LIMIT == ok)
|
||||
{
|
||||
mprint("Too many connections to the server, try later\n");
|
||||
return -1;
|
||||
}
|
||||
else if (ERROR == ok)
|
||||
{
|
||||
mprint("Internal server error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} while(ok != PASSWORD);
|
||||
|
||||
printf("Enter password: ");
|
||||
fflush(stdout);
|
||||
|
||||
char *p = pw;
|
||||
while ((unsigned)(p - pw) < sizeof(pw) && ((*p = fgetc(stdin)) != '\n'))
|
||||
p++;
|
||||
len = p - pw; /* without \n */
|
||||
|
||||
if (write_block(sd, PASSWORD, pw, len) < 0)
|
||||
return -1;
|
||||
|
||||
if (read_byte(sd, &ok) != 1)
|
||||
return -1;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] ");
|
||||
pr_command(ok);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
if (UNKNOWN_COMMAND == ok)
|
||||
{
|
||||
printf("Wrong password\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
else if (ERROR == ok)
|
||||
{
|
||||
mprint("Internal server error\n");
|
||||
return -1;
|
||||
}
|
||||
} while(OK != ok);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int start_tcp_srv(const char *port, const char *pwd)
|
||||
{
|
||||
if (NULL == port)
|
||||
@@ -436,33 +534,9 @@ int start_tcp_srv(const char *port, const char *pwd)
|
||||
|
||||
free(cliaddr);
|
||||
|
||||
if (pwd != NULL && (rc = check_password(sockfd, pwd)) <= 0)
|
||||
goto close_conn;
|
||||
if (check_password(sockfd, pwd) > 0)
|
||||
break;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] OK\n");
|
||||
#endif
|
||||
if (write_byte(sockfd, OK) != 1)
|
||||
goto close_conn;
|
||||
|
||||
char c;
|
||||
size_t len = BUFFER_SIZE;
|
||||
char buf[BUFFER_SIZE];
|
||||
|
||||
do {
|
||||
if (read_block(sockfd, &c, buf, &len) <= 0)
|
||||
goto close_conn;
|
||||
} while (c != BIN_MODE);
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] OK\n");
|
||||
#endif
|
||||
if (write_byte(sockfd, OK) != 1)
|
||||
goto close_conn;
|
||||
|
||||
break;
|
||||
|
||||
close_conn:
|
||||
mprint("Connection closed\n");
|
||||
#if _WIN32
|
||||
closesocket(sockfd);
|
||||
@@ -482,43 +556,33 @@ close_conn:
|
||||
|
||||
int check_password(int fd, const char *pwd)
|
||||
{
|
||||
assert(pwd != NULL);
|
||||
|
||||
char c;
|
||||
int rc;
|
||||
size_t len;
|
||||
char buf[BUFFER_SIZE];
|
||||
size_t len = BUFFER_SIZE;
|
||||
static char buf[BUFFER_SIZE + 1];
|
||||
|
||||
while(1)
|
||||
{
|
||||
len = BUFFER_SIZE;
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] PASSWORD\n");
|
||||
#endif
|
||||
if ((rc = write_byte(fd, PASSWORD)) <= 0)
|
||||
return rc;
|
||||
if ((rc = read_block(fd, &c, buf, &len)) <= 0)
|
||||
return rc;
|
||||
|
||||
if ((rc = read_block(fd, &c, buf, &len)) <= 0)
|
||||
return rc;
|
||||
buf[len] = '\0';
|
||||
|
||||
if (c != PASSWORD)
|
||||
return -1;
|
||||
|
||||
if (strlen(pwd) != len || strncmp(pwd, buf, len) != 0)
|
||||
{
|
||||
sleep(WRONG_PASSWORD_DELAY);
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] WRONG_PASSWORD\n");
|
||||
#endif
|
||||
if ((rc = write_byte(fd, WRONG_PASSWORD)) <= 0)
|
||||
return rc;
|
||||
|
||||
continue;
|
||||
}
|
||||
if (pwd == NULL)
|
||||
return 1;
|
||||
|
||||
if (c == PASSWORD && strcmp(pwd, buf) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[C] Wrong passsword\n");
|
||||
#endif
|
||||
|
||||
#if DEBUG_OUT
|
||||
fprintf(stderr, "[S] PASSWORD\n");
|
||||
#endif
|
||||
if (write_byte(fd, PASSWORD) < 0)
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tcp_bind(const char *port, int *family)
|
||||
@@ -652,7 +716,7 @@ ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len)
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
|
||||
size_t len = atoi(len_str);
|
||||
size_t len = atoi(len_str);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
@@ -679,8 +743,11 @@ ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len)
|
||||
nread += rc;
|
||||
|
||||
#if DEBUG_OUT
|
||||
fwrite(buf, sizeof(char), len, stderr);
|
||||
fprintf(stderr, " ");
|
||||
if (*command != BIN_DATA && *command != BIN_HEADER)
|
||||
{
|
||||
fwrite(buf, sizeof(char), len, stderr);
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -734,6 +801,18 @@ void pr_command(char c)
|
||||
case PASSWORD:
|
||||
fprintf(stderr, "PASSWORD");
|
||||
break;
|
||||
case BIN_HEADER:
|
||||
fprintf(stderr, "BIN_HEADER");
|
||||
break;
|
||||
case BIN_DATA:
|
||||
fprintf(stderr, "BIN_DATA");
|
||||
break;
|
||||
case EPG_DATA:
|
||||
fprintf(stderr, "EPG_DATA");
|
||||
break;
|
||||
case PING:
|
||||
fprintf(stderr, "PING");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "UNKNOWN (%d)", (int) c);
|
||||
break;
|
||||
@@ -767,6 +846,10 @@ ssize_t readn(int fd, void *vptr, size_t n)
|
||||
{
|
||||
nread = 0;
|
||||
}
|
||||
else if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if _WIN32
|
||||
@@ -810,11 +893,7 @@ ssize_t writen(int fd, const void *vptr, size_t n)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"send() eror: %ld\n", WSAGetLastError());
|
||||
#else
|
||||
mprint("send() error: %s\n", strerror(errno));
|
||||
#endif
|
||||
handle_write_error();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -897,9 +976,11 @@ int start_upd_srv(const char *addr_str, unsigned port)
|
||||
struct sockaddr_in servaddr;
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_port = htons(port);
|
||||
#ifndef _WIN32
|
||||
if (IN_MULTICAST(addr))
|
||||
servaddr.sin_addr.s_addr = htonl(addr);
|
||||
else
|
||||
#endif
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
|
||||
@@ -961,3 +1042,71 @@ void init_sockets (void)
|
||||
socket_inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_write_error()
|
||||
{
|
||||
#if _WIN32
|
||||
long err = WSAGetLastError();
|
||||
#else
|
||||
char *err = strerror(errno);
|
||||
#endif
|
||||
|
||||
if (srv_sd < 0)
|
||||
return;
|
||||
|
||||
char c = 0;
|
||||
int rc;
|
||||
do {
|
||||
c = 0;
|
||||
rc = read_byte(srv_sd, &c);
|
||||
if (rc < 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"send() eror: %ld\n", err);
|
||||
#else
|
||||
mprint("send() error: %s\n", err);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
} while (rc > 0 && c == PING);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case PASSWORD:
|
||||
mprint("Wrong password (use -tcppassword)\n");
|
||||
break;
|
||||
case CONN_LIMIT:
|
||||
mprint("Too many connections to the server, please wait\n");
|
||||
break;
|
||||
case ERROR:
|
||||
mprint("Internal server error");
|
||||
break;
|
||||
default:
|
||||
#if _WIN32
|
||||
wprintf(L"send() eror: %ld\n", err);
|
||||
#else
|
||||
mprint("send() error: %s\n", err);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int set_nonblocking(int fd)
|
||||
{
|
||||
int f;
|
||||
#ifdef O_NONBLOCK
|
||||
if ((f = fcntl(fd, F_GETFL, 0)) < 0)
|
||||
f = 0;
|
||||
|
||||
return fcntl(fd, F_SETFL, f | O_NONBLOCK);
|
||||
#else
|
||||
f = 1;
|
||||
#if _WIN32
|
||||
return ioctlsocket(fd, FIONBIO, &f);
|
||||
#else
|
||||
return ioctl(fd, FIONBIO, &f);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3,11 +3,24 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
void connect_to_srv(const char *addr, const char *port, const char *cc_desc);
|
||||
void connect_to_srv(const char *addr, const char *port, const char *cc_desc, const char *pwd);
|
||||
|
||||
void net_send_header(const unsigned char *data, size_t len);
|
||||
int net_send_cc(const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub);
|
||||
|
||||
void net_check_conn();
|
||||
|
||||
void net_send_epg(
|
||||
const char *start,
|
||||
const char *stop,
|
||||
const char *title,
|
||||
const char *desc,
|
||||
const char *lang,
|
||||
const char *category
|
||||
);
|
||||
|
||||
int net_tcp_read(int socket, void *buffer, size_t length);
|
||||
|
||||
int start_tcp_srv(const char *port, const char *pwd);
|
||||
|
||||
int start_upd_srv(const char *addr, unsigned port);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "png.h"
|
||||
#include "lib_ccx.h"
|
||||
#ifdef ENABLE_OCR
|
||||
#include "platform.h"
|
||||
#include "capi.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "allheaders.h"
|
||||
#include <dirent.h>
|
||||
#include "spupng_encoder.h"
|
||||
|
||||
#include "ccx_encoders_helpers.h"
|
||||
#undef OCR_DEBUG
|
||||
struct ocrCtx
|
||||
{
|
||||
TessBaseAPI* api;
|
||||
@@ -63,11 +63,12 @@ static int search_language_pack(const char *dirname,const char *lang)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void delete_ocr (struct ocrCtx* ctx)
|
||||
void delete_ocr (void** arg)
|
||||
{
|
||||
struct ocrCtx* ctx = *arg;
|
||||
TessBaseAPIEnd(ctx->api);
|
||||
TessBaseAPIDelete(ctx->api);
|
||||
freep(&ctx);
|
||||
freep(arg);
|
||||
}
|
||||
void* init_ocr(int lang_index)
|
||||
{
|
||||
@@ -93,24 +94,58 @@ void* init_ocr(int lang_index)
|
||||
/* select english */
|
||||
lang_index = 1;
|
||||
}
|
||||
ret = TessBaseAPIInit3(ctx->api,"", language[lang_index]);
|
||||
|
||||
ret = TessBaseAPIInit3(ctx->api, NULL, language[lang_index]);
|
||||
if(ret < 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
return ctx;
|
||||
fail:
|
||||
delete_ocr(ctx);
|
||||
delete_ocr((void**)&ctx);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
int ignore_alpha_at_edge(png_byte *alpha, unsigned char* indata, int w, int h, PIX *in, PIX **out)
|
||||
{
|
||||
int i, j, index, start_y, end_y;
|
||||
int find_end_x = CCX_FALSE;
|
||||
BOX* cropWindow;
|
||||
for (j = 1; j < w-1; j++)
|
||||
{
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
index = indata[i * w + (j)];
|
||||
if(alpha[index] != 0)
|
||||
{
|
||||
if(find_end_x == CCX_FALSE)
|
||||
{
|
||||
start_y = j;
|
||||
find_end_x = CCX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
end_y = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cropWindow = boxCreate(start_y, 0, (w - (start_y + ( w - end_y) )), h - 1);
|
||||
*out = pixClipRectangle(in, cropWindow, NULL);
|
||||
boxDestroy(&cropWindow);
|
||||
|
||||
return 0;
|
||||
}
|
||||
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h)
|
||||
{
|
||||
PIX *pix;
|
||||
PIX *pix = NULL;
|
||||
PIX *cpix = NULL;
|
||||
char*text_out= NULL;
|
||||
int i,j,index;
|
||||
unsigned int wpl;
|
||||
unsigned int *data,*ppixel;
|
||||
BOOL tess_ret = FALSE;
|
||||
struct ocrCtx* ctx = arg;
|
||||
pix = pixCreate(w, h, 32);
|
||||
if(pix == NULL)
|
||||
@@ -133,13 +168,24 @@ char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* i
|
||||
ppixel++;
|
||||
}
|
||||
}
|
||||
|
||||
text_out = TessBaseAPIProcessPage(ctx->api, pix, 0, NULL, NULL, 0);
|
||||
if(!text_out)
|
||||
ignore_alpha_at_edge(alpha, indata, w, h, pix, &cpix);
|
||||
#ifdef OCR_DEBUG
|
||||
{
|
||||
char str[128] = "";
|
||||
static int i = 0;
|
||||
sprintf(str,"temp/file_c_%d.png",i);
|
||||
pixWrite(str, cpix, IFF_PNG);
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
TessBaseAPISetImage2(ctx->api, cpix);
|
||||
tess_ret = TessBaseAPIRecognize(ctx->api, NULL);
|
||||
if( tess_ret != 0)
|
||||
printf("\nsomething messy\n");
|
||||
|
||||
//TessDeleteText(text_out);
|
||||
pixDestroy(&pix);
|
||||
text_out = TessBaseAPIGetUTF8Text(ctx->api);
|
||||
pixDestroy(&pix);
|
||||
pixDestroy(&cpix);
|
||||
|
||||
return text_out;
|
||||
}
|
||||
@@ -207,7 +253,7 @@ static int quantize_map(png_byte *alpha, png_color *palette,
|
||||
/* sorted in increasing order of intensity */
|
||||
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
|
||||
|
||||
#if OCR_DEBUG
|
||||
#ifdef OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("Intensity ordered table\n");
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
@@ -240,7 +286,7 @@ static int quantize_map(png_byte *alpha, png_color *palette,
|
||||
histogram[iot[max_ind]] = 0;
|
||||
}
|
||||
|
||||
#if OCR_DEBUG
|
||||
#ifdef OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("max redundant intensities table\n");
|
||||
for (int i = 0; i < max_color; i++)
|
||||
{
|
||||
@@ -276,7 +322,7 @@ static int quantize_map(png_byte *alpha, png_color *palette,
|
||||
}
|
||||
|
||||
}
|
||||
#if OCR_DEBUG
|
||||
#ifdef OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("Colors present in quantized Image\n");
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
@@ -296,30 +342,88 @@ int ocr_rect(void* arg, struct cc_bitmap *rect, char **str)
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
palette = (png_color*) malloc(rect->nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
alpha = (png_byte*) malloc(rect->nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* TODO do rectangle wise, one color table should not be used for all rectangles */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect->data[1],rect->nb_colors);
|
||||
|
||||
quantize_map(alpha, palette, rect->data[0], rect->w * rect->h, 3, rect->nb_colors);
|
||||
*str = ocr_bitmap(arg, palette, alpha, rect->data[0], rect->w, rect->h);
|
||||
|
||||
end:
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Call back function used while sorting rectangle by y position
|
||||
* if both rectangle have same y position then x position is considered
|
||||
*/
|
||||
int compare_rect_by_ypos(const void*p1, const void *p2, void*arg)
|
||||
{
|
||||
const struct cc_bitmap* r1 = p1;
|
||||
const struct cc_bitmap* r2 = p2;
|
||||
if(r1->y > r2->y)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (r1->y == r2->y)
|
||||
{
|
||||
if(r1->x > r2->x)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check multiple rectangles and combine them to give one paragraph
|
||||
* for all text detected from rectangles
|
||||
*/
|
||||
char *paraof_ocrtext(struct cc_subtitle *sub)
|
||||
{
|
||||
int i;
|
||||
int len = 0;
|
||||
char *str;
|
||||
struct cc_bitmap* rect;
|
||||
|
||||
shell_sort(sub->data, sub->nb_data, sizeof(struct cc_bitmap), compare_rect_by_ypos, NULL);
|
||||
for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++)
|
||||
{
|
||||
if(rect->ocr_text)
|
||||
len += strlen(rect->ocr_text);
|
||||
}
|
||||
if(len <= 0)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
str = malloc(len+1);
|
||||
if(!str)
|
||||
return NULL;
|
||||
*str = '\0';
|
||||
}
|
||||
|
||||
for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++)
|
||||
{
|
||||
strcat(str, rect->ocr_text);
|
||||
freep(&rect->ocr_text);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
#else
|
||||
char* ocr_bitmap(png_color *palette,png_byte *alpha, unsigned char* indata,unsigned char d,int w, int h)
|
||||
{
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#define OCR_H
|
||||
#include <png.h>
|
||||
|
||||
void delete_ocr (void** arg);
|
||||
void* init_ocr(int lang_index);
|
||||
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h);
|
||||
int ocr_rect(void* arg, struct cc_bitmap *rect, char **str);
|
||||
char *paraof_ocrtext(struct cc_subtitle *sub);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,19 +6,28 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* TODO remove dependency of encoder by removing writeDVDraw from this file */
|
||||
#include "ccx_encoders_structs.h"
|
||||
|
||||
void init_write (struct ccx_s_write *wb,char *filename)
|
||||
void dinit_write(struct ccx_s_write *wb)
|
||||
{
|
||||
if (wb->fh > 0)
|
||||
close(wb->fh);
|
||||
freep(&wb->filename);
|
||||
}
|
||||
int init_write (struct ccx_s_write *wb, char *filename)
|
||||
{
|
||||
memset(wb, 0, sizeof(struct ccx_s_write));
|
||||
wb->fh=-1;
|
||||
wb->filename=filename;
|
||||
wb->filename = filename;
|
||||
mprint ("Creating %s\n", filename);
|
||||
wb->fh = open (filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
if (wb->fh == -1)
|
||||
{
|
||||
return CCX_COMMON_EXIT_FILE_CREATION_FAILED;
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
int writeraw (const unsigned char *data, int length, void *private_data, struct cc_subtitle *sub)
|
||||
{
|
||||
ccx_decoder_608_context *context = private_data;
|
||||
unsigned char* sub_data = NULL;
|
||||
// Don't do anything for empty data
|
||||
if (data==NULL)
|
||||
@@ -38,15 +47,9 @@ int writeraw (const unsigned char *data, int length, void *private_data, struct
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile)
|
||||
{
|
||||
if (closefile && wb!=NULL && wb->fh!=-1 && !ctx->cc_to_stdout)
|
||||
close (wb->fh);
|
||||
}
|
||||
|
||||
void writeDVDraw (const unsigned char *data1, int length1,
|
||||
const unsigned char *data2, int length2,
|
||||
struct ccx_s_write *wb)
|
||||
struct cc_subtitle *sub)
|
||||
{
|
||||
/* these are only used by DVD raw mode: */
|
||||
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
|
||||
@@ -55,43 +58,43 @@ void writeDVDraw (const unsigned char *data1, int length1,
|
||||
|
||||
if (datacount==0)
|
||||
{
|
||||
write (wb->fh,DVD_HEADER,sizeof (DVD_HEADER));
|
||||
writeraw (DVD_HEADER, sizeof (DVD_HEADER), NULL, sub);
|
||||
if (loopcount==1)
|
||||
write (wb->fh,lc1,sizeof (lc1));
|
||||
writeraw (lc1, sizeof (lc1), NULL, sub);
|
||||
if (loopcount==2)
|
||||
write (wb->fh,lc2,sizeof (lc2));
|
||||
writeraw (lc2, sizeof (lc2), NULL, sub);
|
||||
if (loopcount==3)
|
||||
{
|
||||
write (wb->fh,lc3,sizeof (lc3));
|
||||
writeraw (lc3, sizeof (lc3), NULL, sub);
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
writeraw (data2, length2, NULL, sub);
|
||||
}
|
||||
if (loopcount>3)
|
||||
{
|
||||
write (wb->fh,lc4,sizeof (lc4));
|
||||
writeraw (lc4, sizeof (lc4), NULL, sub);
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
writeraw (data2, length2, NULL, sub);
|
||||
}
|
||||
}
|
||||
datacount++;
|
||||
write (wb->fh,lc5,sizeof (lc5));
|
||||
writeraw (lc5, sizeof (lc5), NULL, sub);
|
||||
if (data1 && length1)
|
||||
write (wb->fh,data1,length1);
|
||||
writeraw (data1, length1, NULL, sub);
|
||||
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
|
||||
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
|
||||
((loopcount > 3) && (datacount < 15)))
|
||||
{
|
||||
write (wb->fh,lc6,sizeof (lc6));
|
||||
writeraw (lc6, sizeof(lc6), NULL, sub);
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
writeraw (data2, length2, NULL, sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (loopcount==1)
|
||||
{
|
||||
write (wb->fh,lc6,sizeof (lc6));
|
||||
writeraw (lc6, sizeof(lc6), NULL, sub);
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
writeraw (data2, length2, NULL, sub);
|
||||
}
|
||||
loopcount++;
|
||||
datacount=0;
|
||||
@@ -102,25 +105,24 @@ void writeDVDraw (const unsigned char *data1, int length1,
|
||||
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
|
||||
const unsigned char *data2, int length2, struct cc_subtitle *sub)
|
||||
{
|
||||
struct ccx_decoder_608_context *field_1 = ctx->context_cc608_field_1;
|
||||
struct ccx_decoder_608_context *field_2 = ctx->context_cc608_field_2;
|
||||
struct ccx_s_write *wbout1 = ctx->wbout1;
|
||||
field_1->out = ctx->wbout1 ;
|
||||
field_2->out = ctx->wbout2 ;
|
||||
if (ctx->write_format==CCX_OF_DVDRAW)
|
||||
writeDVDraw (data1, length1, data2, length2, wbout1);
|
||||
writeDVDraw (data1, length1, data2, length2, sub);
|
||||
else /* Broadcast raw or any non-raw */
|
||||
{
|
||||
if (length1 && ctx->extract != 2)
|
||||
{
|
||||
ctx->writedata(data1, length1, field_1, sub);
|
||||
ctx->current_field = 1;
|
||||
ctx->writedata(data1, length1, ctx, sub);
|
||||
}
|
||||
if (length2)
|
||||
{
|
||||
ctx->current_field = 2;
|
||||
if (ctx->extract != 1)
|
||||
ctx->writedata(data2, length2, field_2, sub);
|
||||
ctx->writedata(data2, length2, ctx, sub);
|
||||
else // User doesn't want field 2 data, but we want XDS.
|
||||
ctx->writedata (data2,length2,NULL, sub);
|
||||
{
|
||||
ctx->writedata (data2, length2, ctx, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,12 +132,11 @@ void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int lengt
|
||||
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data, struct cc_subtitle *sub)
|
||||
{
|
||||
static LLONG prevfts = -1;
|
||||
LLONG currfts = fts_now + fts_global;
|
||||
LLONG currfts = ctx->timing->fts_now + ctx->timing->fts_global;
|
||||
static uint16_t cbcount = 0;
|
||||
static int cbempty=0;
|
||||
static unsigned char cbbuffer[0xFFFF*3]; // TODO: use malloc
|
||||
static unsigned char cbheader[8+2];
|
||||
struct ccx_s_write *wbout1 = ctx->wbout1;
|
||||
|
||||
if ( (prevfts != currfts && prevfts != -1)
|
||||
|| data == NULL
|
||||
|
||||
@@ -1,60 +1,13 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "utility.h"
|
||||
#include "activity.h"
|
||||
#include "ccx_encoders_helpers.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
|
||||
static int inputfile_capacity=0;
|
||||
|
||||
static const char *DEF_VAL_STARTCREDITSNOTBEFORE="0";
|
||||
static const char *DEF_VAL_STARTCREDITSNOTAFTER="5:00"; // To catch the theme after the teaser in TV shows
|
||||
static const char *DEF_VAL_STARTCREDITSFORATLEAST="2";
|
||||
static const char *DEF_VAL_STARTCREDITSFORATMOST="5";
|
||||
static const char *DEF_VAL_ENDCREDITSFORATLEAST="2";
|
||||
static const char *DEF_VAL_ENDCREDITSFORATMOST="5";
|
||||
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt)
|
||||
{
|
||||
unsigned ss=0, mm=0, hh=0;
|
||||
int value=-1;
|
||||
int colons=0;
|
||||
const char *c=s;
|
||||
while (*c)
|
||||
{
|
||||
if (*c==':')
|
||||
{
|
||||
if (value==-1) // : at the start, or ::, etc
|
||||
return -1;
|
||||
colons++;
|
||||
if (colons>2) // Max 2, for HH:MM:SS
|
||||
return -1;
|
||||
hh=mm;
|
||||
mm=ss;
|
||||
ss=value;
|
||||
value=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isdigit (*c)) // Only : or digits, so error
|
||||
return -1;
|
||||
if (value==-1)
|
||||
value=*c-'0';
|
||||
else
|
||||
value=value*10+*c-'0';
|
||||
}
|
||||
c++;
|
||||
}
|
||||
hh = mm;
|
||||
mm = ss;
|
||||
ss = value;
|
||||
if (mm > 59 || ss > 59)
|
||||
return -1;
|
||||
bt->set = 1;
|
||||
bt->hh = hh;
|
||||
bt->mm = mm;
|
||||
bt->ss = ss;
|
||||
LLONG secs = (hh * 3600 + mm * 60 + ss);
|
||||
bt->time_in_ms = secs*1000;
|
||||
return 0;
|
||||
}
|
||||
int process_cap_file (char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -218,11 +171,14 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
|
||||
|
||||
if (strcmp (format,"srt")==0)
|
||||
opt->write_format=CCX_OF_SRT;
|
||||
else if (strcmp(format, "webvtt") == 0)
|
||||
opt->write_format = CCX_OF_WEBVTT;
|
||||
else if (strcmp (format,"sami")==0 || strcmp (format,"smi")==0)
|
||||
opt->write_format=CCX_OF_SAMI;
|
||||
else if (strcmp (format,"transcript")==0 || strcmp (format,"txt")==0)
|
||||
{
|
||||
opt->write_format=CCX_OF_TRANSCRIPT;
|
||||
opt->settings_dtvcc.no_rollup = 1;
|
||||
}
|
||||
else if (strcmp (format,"timedtranscript")==0 || strcmp (format,"ttxt")==0)
|
||||
{
|
||||
@@ -239,10 +195,10 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
|
||||
}
|
||||
else if (strcmp (format,"report")==0)
|
||||
{
|
||||
opt->write_format=CCX_OF_NULL;
|
||||
opt->messages_target=0;
|
||||
opt->print_file_reports=1;
|
||||
opt->ts_autoprogram=1;
|
||||
opt->write_format = CCX_OF_NULL;
|
||||
opt->messages_target = 0;
|
||||
opt->print_file_reports = 1;
|
||||
opt->demux_cfg.ts_allprogram = CCX_TRUE;
|
||||
}
|
||||
else if (strcmp (format,"raw")==0)
|
||||
opt->write_format=CCX_OF_RAW;
|
||||
@@ -256,6 +212,8 @@ void set_output_format (struct ccx_s_options *opt, const char *format)
|
||||
opt->write_format=CCX_OF_DVDRAW;
|
||||
else if (strcmp (format,"spupng")==0)
|
||||
opt->write_format=CCX_OF_SPUPNG;
|
||||
else if (strcmp (format,"simplexml")==0)
|
||||
opt->write_format=CCX_OF_SIMPLE_XML;
|
||||
else
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "Unknown output file format: %s\n", format);
|
||||
}
|
||||
@@ -264,39 +222,39 @@ void set_input_format (struct ccx_s_options *opt, const char *format)
|
||||
{
|
||||
if (opt->input_source == CCX_DS_TCP && strcmp(format, "bin")!=0)
|
||||
{
|
||||
mprint("Intput format is changed to bin\n");
|
||||
mprint("Input format is changed to bin\n");
|
||||
format = "bin";
|
||||
}
|
||||
|
||||
while (*format=='-')
|
||||
format++;
|
||||
if (strcmp (format,"es")==0) // Does this actually do anything?
|
||||
opt->auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
else if (strcmp(format, "ts") == 0)
|
||||
{
|
||||
opt->auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->m2ts = 0;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->demux_cfg.m2ts = 0;
|
||||
}
|
||||
else if (strcmp(format, "m2ts") == 0)
|
||||
{
|
||||
opt->auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->m2ts = 1;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->demux_cfg.m2ts = 1;
|
||||
}
|
||||
else if (strcmp (format,"ps")==0 || strcmp (format,"nots")==0)
|
||||
opt->auto_stream = CCX_SM_PROGRAM;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_PROGRAM;
|
||||
else if (strcmp (format,"asf")==0 || strcmp (format,"dvr-ms")==0)
|
||||
opt->auto_stream = CCX_SM_ASF;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_ASF;
|
||||
else if (strcmp (format,"wtv")==0)
|
||||
opt->auto_stream = CCX_SM_WTV;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_WTV;
|
||||
else if (strcmp (format,"raw")==0)
|
||||
opt->auto_stream = CCX_SM_MCPOODLESRAW;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_MCPOODLESRAW;
|
||||
else if (strcmp (format,"bin")==0)
|
||||
opt->auto_stream = CCX_SM_RCWT;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_RCWT;
|
||||
else if (strcmp (format,"mp4")==0)
|
||||
opt->auto_stream = CCX_SM_MP4;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_MP4;
|
||||
#ifdef WTV_DEBUG
|
||||
else if (strcmp (format,"hex")==0)
|
||||
opt->auto_stream = CCX_SM_HEX_DUMP;
|
||||
opt->demux_cfg.auto_stream = CCX_SM_HEX_DUMP;
|
||||
#endif
|
||||
else
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "Unknown input file format: %s\n", format);
|
||||
@@ -337,6 +295,8 @@ void usage (void)
|
||||
mprint ("Output will be one single file (either raw or srt). Use this if you made your\n");
|
||||
mprint ("recording in several cuts (to skip commercials for example) but you want one\n");
|
||||
mprint ("subtitle file with contiguous timing.\n\n");
|
||||
mprint ("Effect output files\n");
|
||||
mprint (" -outinterval x output in interval of x seconds\n");
|
||||
mprint ("Network support:\n");
|
||||
mprint (" -udp port: Read the input via UDP (listening in the specified port)\n");
|
||||
mprint (" instead of reading a file.\n\n");
|
||||
@@ -357,10 +317,19 @@ void usage (void)
|
||||
mprint (" (DEFAULT is -1)\n");
|
||||
mprint (" -cc2: When in srt/sami mode, process captions in channel 2\n");
|
||||
mprint (" instead of channel 1.\n");
|
||||
mprint ("-svc --service N,N...: Enabled CEA-708 captions processing for the listed\n");
|
||||
mprint (" services. The parameter is a command delimited list\n");
|
||||
mprint ("-svc --service N1[cs1],N2[cs2]...:\n");
|
||||
mprint (" Enable CEA-708 (DTVCC) captions processing for the listed\n");
|
||||
mprint (" services. The parameter is a comma delimited list\n");
|
||||
mprint (" of services numbers, such as \"1,2\" to process the\n");
|
||||
mprint (" primary and secondary language services.\n");
|
||||
mprint (" Pass \"all\" to process all services found.\n");
|
||||
mprint ("\n");
|
||||
mprint (" If captions in a service are stored in 16-bit encoding, you can\n");
|
||||
mprint (" specify what charset or encoding was used. Pass its name after\n");
|
||||
mprint (" service number (e.g. \"1[EUC-KR],3\" or \"all[EUC-KR]\") and it will\n");
|
||||
mprint (" encode specified charset to UTF-8 using iconv. See iconv documentation\n");
|
||||
mprint (" to check if required encoding/charset is supported.\n");
|
||||
mprint ("\n");
|
||||
mprint ("In general, if you want English subtitles you don't need to use these options\n");
|
||||
mprint ("as they are broadcast in field 1, channel 1. If you want the second language\n");
|
||||
mprint ("(usually Spanish) you may need to try -2, or -cc2, or both.\n\n");
|
||||
@@ -386,6 +355,7 @@ void usage (void)
|
||||
mprint (" -out=format\n\n");
|
||||
mprint (" where format is one of these:\n");
|
||||
mprint (" srt -> SubRip (default, so not actually needed).\n");
|
||||
mprint (" webvtt -> WebVTT format\n");
|
||||
mprint (" sami -> MS Synchronized Accesible Media Interface.\n");
|
||||
mprint (" bin -> CC data in CCExtractor's own binary format.\n");
|
||||
mprint (" raw -> CC data in McPoodle's Broadcast format.\n");
|
||||
@@ -402,7 +372,7 @@ void usage (void)
|
||||
mprint (" report -> Prints to stdout information about captions\n");
|
||||
mprint (" in specified input. Don't produce any file\n");
|
||||
mprint (" output\n\n");
|
||||
mprint (" Note: Teletext output can only be srt, txt or ttxt for now.\n\n");
|
||||
mprint (" Note: Teletext output can only be srt, webvtt, txt or ttxt for now.\n\n");
|
||||
|
||||
mprint ("Options that affect how input files will be processed.\n");
|
||||
|
||||
@@ -496,11 +466,11 @@ void usage (void)
|
||||
mprint (" -utf8: Encode subtitles in UTF-8 (no longer needed.\n");
|
||||
mprint (" because UTF-8 is now the default).\n");
|
||||
mprint (" -latin1: Encode subtitles in Latin-1\n");
|
||||
mprint (" -nofc --nofontcolor: For .srt/.sami, don't add font color tags.\n");
|
||||
mprint ("-nots --notypesetting: For .srt/.sami, don't add typesetting tags.\n");
|
||||
mprint (" -nofc --nofontcolor: For .srt/.sami/.vtt, don't add font color tags.\n");
|
||||
mprint ("-nots --notypesetting: For .srt/.sami/.vtt, don't add typesetting tags.\n");
|
||||
mprint (" -trim: Trim lines.\n");
|
||||
mprint (" -dc --defaultcolor: Select a different default color (instead of\n");
|
||||
mprint (" white). This causes all output in .srt/.smi\n");
|
||||
mprint (" white). This causes all output in .srt/.smi/.vtt\n");
|
||||
mprint (" files to have a font tag, which makes the files\n");
|
||||
mprint (" larger. Add the color you want in RGB, such as\n");
|
||||
mprint (" -dc #FF0000 for red.\n");
|
||||
@@ -532,9 +502,10 @@ void usage (void)
|
||||
mprint (" terminator.\n");
|
||||
mprint (" -autodash: Based on position on screen, attempt to determine\n");
|
||||
mprint (" the different speakers and a dash (-) when each\n");
|
||||
mprint (" of them talks (.srt only, -trim required).\n");
|
||||
mprint (" -xmltv: produce an XMLTV file containing the EPG data from\n");
|
||||
mprint (" the source TS file.\n\n");
|
||||
mprint (" of them talks (.srt/.vtt only, -trim required).\n");
|
||||
mprint (" -xmltv mode: produce an XMLTV file containing the EPG data from\n");
|
||||
mprint (" the source TS file. Mode: 1 = full output\n");
|
||||
mprint (" 2 = live output. 3 = both\n\n");
|
||||
|
||||
mprint ("Options that affect how ccextractor reads and writes (buffering):\n");
|
||||
|
||||
@@ -566,7 +537,7 @@ void usage (void)
|
||||
|
||||
mprint ("Options that affect timing:\n");
|
||||
|
||||
mprint (" -delay ms: For srt/sami, add this number of milliseconds to\n");
|
||||
mprint (" -delay ms: For srt/sami/webvtt, add this number of milliseconds to\n");
|
||||
mprint (" all times. For example, -delay 400 makes subtitles\n");
|
||||
mprint (" appear 400ms late. You can also use negative numbers\n");
|
||||
mprint (" to make subs appear early.\n");
|
||||
@@ -592,14 +563,14 @@ void usage (void)
|
||||
|
||||
mprint ("Options that affect which codec is to be used have to be searched in input\n");
|
||||
|
||||
mprint (" If codec type is not selected then first elementry stream suitable for \n"
|
||||
mprint (" If codec type is not selected then first elementary stream suitable for \n"
|
||||
" subtitle is selected, please consider -teletext -noteletext override this\n"
|
||||
" option.\n"
|
||||
" -codec dvbsub select the dvb subtitle from all elementry stream,\n"
|
||||
" -codec dvbsub select the dvb subtitle from all elementary stream,\n"
|
||||
" if stream of dvb subtitle type is not found then \n"
|
||||
" nothing is selected and no subtitle is generated\n"
|
||||
" -nocodec dvbsub ignore dvb subtitle and follow default behaviour\n"
|
||||
" -codec teletext select the teletext subtitle from elementry stream\n"
|
||||
" -codec teletext select the teletext subtitle from elementary stream\n"
|
||||
" -nocodec teletext ignore teletext subtitle\n"
|
||||
" NOTE: option given in form -foo=bar ,-foo = bar and --foo=bar are invalid\n"
|
||||
" valid option are only in form -foo bar\n"
|
||||
@@ -658,6 +629,7 @@ void usage (void)
|
||||
mprint (" file. (Only for TS/ASF files at the moment.)\n");
|
||||
mprint (" -parsePAT: Print Program Association Table dump.\n");
|
||||
mprint (" -parsePMT: Print Program Map Table dump.\n");
|
||||
mprint(" -dumpdef: Hex-dump defective TS packets.\n");
|
||||
mprint (" -investigate_packets: If no CC packets are detected based on the PMT, try\n");
|
||||
mprint (" to find data in all packets by scanning.\n\n");
|
||||
|
||||
@@ -738,30 +710,95 @@ void usage (void)
|
||||
mprint(" ...\n");
|
||||
}
|
||||
|
||||
void parse_708services (char *s)
|
||||
void parse_708_services (struct ccx_s_options *opts, char *s)
|
||||
{
|
||||
char *c, *e, *l;
|
||||
if (s==NULL)
|
||||
const char *all = "all";
|
||||
size_t all_len = strlen(all);
|
||||
int diff = strncmp(s, all, all_len);
|
||||
if (!diff) {
|
||||
size_t s_len = strlen(s);
|
||||
char *charset = NULL;
|
||||
if (s_len > all_len + 2) // '[' and ']'
|
||||
charset = strndup(s + all_len + 1, s_len - all_len - 2);
|
||||
|
||||
opts->settings_dtvcc.enabled = 1;
|
||||
opts->enc_cfg.dtvcc_extract = 1;
|
||||
opts->enc_cfg.all_services_charset = charset;
|
||||
|
||||
opts->enc_cfg.services_charsets = (char **) calloc(sizeof(char *), CCX_DTVCC_MAX_SERVICES);
|
||||
if (!opts->enc_cfg.services_charsets)
|
||||
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "parse_708_services");
|
||||
memset(opts->enc_cfg.services_charsets, 0, CCX_DTVCC_MAX_SERVICES * sizeof(char *));
|
||||
|
||||
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
|
||||
{
|
||||
opts->settings_dtvcc.services_enabled[i] = 1;
|
||||
opts->enc_cfg.services_enabled[i] = 1;
|
||||
}
|
||||
|
||||
opts->settings_dtvcc.active_services_count = CCX_DTVCC_MAX_SERVICES;
|
||||
return;
|
||||
l=s+strlen (s);
|
||||
for (c=s; c<l && *c; )
|
||||
}
|
||||
|
||||
char *c, *e, *l;
|
||||
if (s == NULL)
|
||||
return;
|
||||
l = s + strlen(s);
|
||||
for (c = s; c < l && *c; )
|
||||
{
|
||||
int svc=-1;
|
||||
while (*c && !isdigit (*c))
|
||||
int svc = -1;
|
||||
while (*c && !isdigit(*c))
|
||||
c++;
|
||||
if (!*c) // We're done
|
||||
break;
|
||||
e=c;
|
||||
e = c;
|
||||
while (isdigit (*e))
|
||||
e++;
|
||||
*e=0;
|
||||
svc=atoi (c);
|
||||
if (svc<1 || svc>CCX_DECODERS_708_MAX_SERVICES)
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "Invalid service number (%d), valid range is 1-%d.",svc,CCX_DECODERS_708_MAX_SERVICES);
|
||||
cea708services[svc-1]=1;
|
||||
do_cea708=1;
|
||||
c=e+1;
|
||||
int charset_start_found = (*e == '[');
|
||||
*e = 0;
|
||||
svc = atoi(c);
|
||||
if (svc < 1 || svc > CCX_DTVCC_MAX_SERVICES)
|
||||
fatal(EXIT_MALFORMED_PARAMETER,
|
||||
"[CEA-708] Malformed parameter: "
|
||||
"Invalid service number (%d), valid range is 1-%d.", svc, CCX_DTVCC_MAX_SERVICES);
|
||||
opts->settings_dtvcc.services_enabled[svc - 1] = 1;
|
||||
opts->enc_cfg.services_enabled[svc - 1] = 1;
|
||||
opts->settings_dtvcc.enabled = 1;
|
||||
opts->enc_cfg.dtvcc_extract = 1;
|
||||
opts->settings_dtvcc.active_services_count++;
|
||||
|
||||
if (!opts->enc_cfg.services_charsets)
|
||||
{
|
||||
opts->enc_cfg.services_charsets = (char **) calloc(sizeof(char *), CCX_DTVCC_MAX_SERVICES);
|
||||
if (!opts->enc_cfg.services_charsets)
|
||||
ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "parse_708_services");
|
||||
memset(opts->enc_cfg.services_charsets, 0, CCX_DTVCC_MAX_SERVICES * sizeof(char *));
|
||||
}
|
||||
|
||||
e = e + 1;
|
||||
c = e;
|
||||
|
||||
if (!charset_start_found)
|
||||
continue;
|
||||
|
||||
while (*e && *e != ']' && *e != ',')
|
||||
e++;
|
||||
if (*e == ']')
|
||||
{
|
||||
char *charset = strndup(c, e - c);
|
||||
if (strlen(charset))
|
||||
opts->enc_cfg.services_charsets[svc - 1] = charset;
|
||||
c = e + 1;
|
||||
}
|
||||
else if (!*e)
|
||||
{
|
||||
fatal(EXIT_MALFORMED_PARAMETER,
|
||||
"[CEA-708] Malformed parameter: missing closing ] in CEA-708 services list");
|
||||
}
|
||||
}
|
||||
if (!opts->settings_dtvcc.active_services_count)
|
||||
fatal(EXIT_MALFORMED_PARAMETER,
|
||||
"[CEA-708] Malformed parameter: no services");
|
||||
}
|
||||
|
||||
long atol_size (char *s)
|
||||
@@ -789,16 +826,6 @@ int atoi_hex (char *s)
|
||||
|
||||
int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
{
|
||||
char *cea708_service_list=NULL; // List CEA-708 services
|
||||
|
||||
// Sensible default values for credits
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &opt->startcreditsnotbefore);
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &opt->startcreditsnotafter);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &opt->startcreditsforatleast);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &opt->startcreditsforatmost);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &opt->endcreditsforatleast);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &opt->endcreditsforatmost);
|
||||
|
||||
// Parse parameters
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
@@ -859,11 +886,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-bom") == 0){
|
||||
opt->no_bom = 0;
|
||||
opt->enc_cfg.no_bom = 0;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-nobom") == 0){
|
||||
opt->no_bom = 1;
|
||||
opt->enc_cfg.no_bom = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-nots")==0 ||
|
||||
@@ -899,11 +926,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
i++;
|
||||
if(!strcmp (argv[i],"teletext"))
|
||||
{
|
||||
opt->codec = CCX_CODEC_TELETEXT;
|
||||
opt->demux_cfg.codec = CCX_CODEC_TELETEXT;
|
||||
}
|
||||
else if(!strcmp (argv[i],"dvbsub"))
|
||||
{
|
||||
opt->codec = CCX_CODEC_DVB;
|
||||
opt->demux_cfg.codec = CCX_CODEC_DVB;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -918,11 +945,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
i++;
|
||||
if(!strcmp (argv[i],"teletext"))
|
||||
{
|
||||
opt->nocodec = CCX_CODEC_TELETEXT;
|
||||
opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT;
|
||||
}
|
||||
else if(!strcmp (argv[i],"dvbsub"))
|
||||
{
|
||||
opt->nocodec = CCX_CODEC_DVB;
|
||||
opt->demux_cfg.nocodec = CCX_CODEC_DVB;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -933,7 +960,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
/* Output file formats */
|
||||
if (strcmp (argv[i],"-srt")==0 ||
|
||||
strcmp (argv[i],"-dvdraw")==0 ||
|
||||
strcmp (argv[i],"-sami")==0 || strcmp (argv[i],"-smi")==0 ||
|
||||
strcmp(argv[i], "-sami") == 0 || strcmp(argv[i], "-smi") == 0 || strcmp(argv[i], "-webvtt") == 0 ||
|
||||
strcmp (argv[i],"--transcript")==0 || strcmp (argv[i],"-txt")==0 ||
|
||||
strcmp (argv[i],"--timedtranscript")==0 || strcmp (argv[i],"-ttxt")==0 ||
|
||||
strcmp (argv[i],"-null")==0)
|
||||
@@ -951,14 +978,14 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if ((strcmp (argv[i],"--startcreditstext")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
opt->start_credits_text=argv[i+1];
|
||||
opt->enc_cfg.start_credits_text=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if ((strcmp (argv[i],"--startcreditsnotbefore")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
if (stringztoms (argv[i+1],&opt->startcreditsnotbefore)==-1)
|
||||
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsnotbefore)==-1)
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsnotbefore only accepts SS, MM:SS or HH:MM:SS\n");
|
||||
}
|
||||
@@ -968,7 +995,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if ((strcmp (argv[i],"--startcreditsnotafter")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
if (stringztoms (argv[i+1],&opt->startcreditsnotafter)==-1)
|
||||
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsnotafter)==-1)
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsnotafter only accepts SS, MM:SS or HH:MM:SS\n");
|
||||
}
|
||||
@@ -978,7 +1005,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if ((strcmp (argv[i],"--startcreditsforatleast")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
if (stringztoms (argv[i+1],&opt->startcreditsforatleast)==-1)
|
||||
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsforatleast)==-1)
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsforatleast only accepts SS, MM:SS or HH:MM:SS\n");
|
||||
}
|
||||
@@ -988,7 +1015,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if ((strcmp (argv[i],"--startcreditsforatmost")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
if (stringztoms (argv[i+1],&opt->startcreditsforatmost)==-1)
|
||||
if (stringztoms (argv[i+1],&opt->enc_cfg.startcreditsforatmost)==-1)
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost only accepts SS, MM:SS or HH:MM:SS\n");
|
||||
}
|
||||
@@ -999,14 +1026,14 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if ((strcmp (argv[i],"--endcreditstext")==0 )
|
||||
&& i<argc-1)
|
||||
{
|
||||
opt->end_credits_text=argv[i+1];
|
||||
opt->enc_cfg.end_credits_text=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if ((strcmp (argv[i],"--endcreditsforatleast")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
if (stringztoms (argv[i+1],&opt->endcreditsforatleast)==-1)
|
||||
if (stringztoms (argv[i+1],&opt->enc_cfg.endcreditsforatleast)==-1)
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "--endcreditsforatleast only accepts SS, MM:SS or HH:MM:SS\n");
|
||||
}
|
||||
@@ -1016,7 +1043,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if ((strcmp (argv[i],"--endcreditsforatmost")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
if (stringztoms (argv[i+1],&opt->endcreditsforatmost)==-1)
|
||||
if (stringztoms (argv[i+1],&opt->enc_cfg.endcreditsforatmost)==-1)
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost only accepts SS, MM:SS or HH:MM:SS\n");
|
||||
}
|
||||
@@ -1062,7 +1089,9 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if (strcmp (argv[i],"-noru")==0 ||
|
||||
strcmp (argv[i],"--norollup")==0)
|
||||
{
|
||||
opt->no_rollup = 1;
|
||||
opt->settings_608.no_rollup = 1;
|
||||
opt->settings_dtvcc.no_rollup = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-ru1")==0)
|
||||
@@ -1077,12 +1106,18 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-ru3")==0)
|
||||
{
|
||||
opt->settings_608 .force_rollup = 3;
|
||||
opt->settings_608.force_rollup = 3;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-trim")==0)
|
||||
{
|
||||
opt->trim_subs=1;
|
||||
opt->enc_cfg.trim_subs=1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-outinterval")==0)
|
||||
{
|
||||
opt->out_interval = atoi(argv[i+1]);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"--gui_mode_reports")==0)
|
||||
@@ -1098,14 +1133,14 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
if (strcmp (argv[i],"--sentencecap")==0 ||
|
||||
strcmp (argv[i],"-sc")==0)
|
||||
{
|
||||
opt->sentence_cap=1;
|
||||
opt->enc_cfg.sentence_cap=1;
|
||||
continue;
|
||||
}
|
||||
if ((strcmp (argv[i],"--capfile")==0 ||
|
||||
strcmp (argv[i],"-caf")==0)
|
||||
&& i<argc-1)
|
||||
{
|
||||
opt->sentence_cap=1;
|
||||
opt->enc_cfg.sentence_cap=1;
|
||||
opt->sentence_cap_file=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
@@ -1115,18 +1150,24 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
{
|
||||
if (i==argc-1 // Means no following argument
|
||||
|| !isanumber (argv[i+1])) // Means is not a number
|
||||
opt->ts_forced_program = (unsigned)-1; // Autodetect
|
||||
opt->demux_cfg.ts_forced_program = -1; // Autodetect
|
||||
else
|
||||
{
|
||||
opt->ts_forced_program=atoi_hex (argv[i+1]);
|
||||
opt->ts_forced_program_selected=1;
|
||||
opt->demux_cfg.ts_forced_program=atoi_hex (argv[i+1]);
|
||||
opt->demux_cfg.ts_forced_program_selected=1;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-autoprogram")==0)
|
||||
{
|
||||
opt->ts_autoprogram=1;
|
||||
opt->demux_cfg.ts_autoprogram=1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-multiprogram")==0)
|
||||
{
|
||||
opt->multiprogram = 1;
|
||||
opt->demux_cfg.ts_allprogram = CCX_TRUE;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"--stream")==0 ||
|
||||
@@ -1288,6 +1329,11 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
opt->debug_mask |= CCX_DMT_PMT;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-dumpdef") == 0)
|
||||
{
|
||||
opt->debug_mask |= CCX_DMT_DUMPDEF;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-investigate_packets")==0)
|
||||
{
|
||||
opt->investigate_packets=1;
|
||||
@@ -1326,17 +1372,17 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strstr (argv[i],"-unicode")!=NULL)
|
||||
{
|
||||
opt->encoding=CCX_ENC_UNICODE;
|
||||
opt->enc_cfg.encoding=CCX_ENC_UNICODE;
|
||||
continue;
|
||||
}
|
||||
if (strstr (argv[i],"-utf8")!=NULL)
|
||||
{
|
||||
opt->encoding=CCX_ENC_UTF_8;
|
||||
opt->enc_cfg.encoding=CCX_ENC_UTF_8;
|
||||
continue;
|
||||
}
|
||||
if (strstr (argv[i],"-latin1")!=NULL)
|
||||
{
|
||||
opt->encoding=CCX_ENC_LATIN_1;
|
||||
opt->enc_cfg.encoding=CCX_ENC_LATIN_1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-poc")==0 || strcmp (argv[i],"--usepicorder")==0)
|
||||
@@ -1366,52 +1412,39 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-o")==0 && i<argc-1)
|
||||
{
|
||||
opt->output_filename=argv[i+1];
|
||||
opt->output_filename = argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-cf")==0 && i<argc-1)
|
||||
{
|
||||
opt->out_elementarystream_filename=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-o1")==0 && i<argc-1)
|
||||
{
|
||||
opt->wbout1.filename=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-o2")==0 && i<argc-1)
|
||||
{
|
||||
opt->wbout2.filename=argv[i+1];
|
||||
opt->demux_cfg.out_elementarystream_filename = argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if ( (strcmp (argv[i],"-svc")==0 || strcmp (argv[i],"--service")==0) &&
|
||||
i<argc-1)
|
||||
{
|
||||
cea708_service_list=argv[i+1];
|
||||
parse_708services (cea708_service_list);
|
||||
parse_708_services(opt, argv[i + 1]);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-datapid")==0 && i<argc-1)
|
||||
{
|
||||
opt->ts_cappid = atoi_hex(argv[i+1]);
|
||||
opt->ts_forced_cappid=1;
|
||||
opt->demux_cfg.ts_cappids[opt->demux_cfg.nb_ts_cappid] = atoi_hex(argv[i+1]);
|
||||
opt->demux_cfg.nb_ts_cappid++;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-datastreamtype")==0 && i<argc-1)
|
||||
{
|
||||
opt->ts_datastreamtype = atoi_hex(argv[i+1]);
|
||||
opt->demux_cfg.ts_datastreamtype = atoi_hex(argv[i+1]);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-streamtype")==0 && i<argc-1)
|
||||
{
|
||||
opt->ts_forced_streamtype = atoi_hex(argv[i+1]);
|
||||
opt->demux_cfg.ts_forced_streamtype = atoi_hex(argv[i+1]);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
@@ -1420,14 +1453,13 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
{
|
||||
tlt_config.page = atoi_hex(argv[i+1]);
|
||||
tlt_config.user_page = tlt_config.page;
|
||||
opt->teletext_mode=CCX_TXT_IN_USE;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-UCLA")==0 || strcmp (argv[i],"-ucla")==0)
|
||||
{
|
||||
opt->millis_separator='.';
|
||||
opt->no_bom = 1;
|
||||
opt->enc_cfg.no_bom = 1;
|
||||
if (!opt->transcript_settings.isFinal){
|
||||
opt->transcript_settings.showStartTime = 1;
|
||||
opt->transcript_settings.showEndTime = 1;
|
||||
@@ -1440,7 +1472,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-lf")==0 || strcmp (argv[i],"-LF")==0)
|
||||
{
|
||||
opt->line_terminator_lf = 1;
|
||||
opt->enc_cfg.line_terminator_lf = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-noautotimeref")==0)
|
||||
@@ -1450,7 +1482,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-autodash")==0)
|
||||
{
|
||||
opt->autodash = 1;
|
||||
opt->enc_cfg.autodash = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-xmltv")==0)
|
||||
@@ -1524,14 +1556,12 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-teletext")==0)
|
||||
{
|
||||
opt->codec = CCX_CODEC_TELETEXT;
|
||||
opt->teletext_mode=CCX_TXT_IN_USE;
|
||||
opt->demux_cfg.codec = CCX_CODEC_TELETEXT;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-noteletext")==0)
|
||||
{
|
||||
opt->nocodec = CCX_CODEC_TELETEXT;
|
||||
opt->teletext_mode=CCX_TXT_FORBIDDEN;
|
||||
opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT;
|
||||
continue;
|
||||
}
|
||||
/* Custom transcript */
|
||||
@@ -1587,6 +1617,9 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
|
||||
set_output_format(opt, "bin");
|
||||
|
||||
opt->xmltv = 2;
|
||||
opt->xmltvliveinterval = 2;
|
||||
|
||||
char *addr = argv[i + 1];
|
||||
if (*addr == '[')
|
||||
{
|
||||
@@ -1657,7 +1690,7 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
activity_report_version();
|
||||
}
|
||||
|
||||
if(opt->sentence_cap)
|
||||
if(opt->enc_cfg.sentence_cap)
|
||||
{
|
||||
if(add_built_in_words())
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory for word list");
|
||||
@@ -1666,14 +1699,10 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
|
||||
ccx_encoders_helpers_perform_shellsort_words();
|
||||
}
|
||||
if(opt->ts_forced_program != -1)
|
||||
opt->ts_forced_program_selected = 1;
|
||||
if(opt->demux_cfg.ts_forced_program != -1)
|
||||
opt->demux_cfg.ts_forced_program_selected = 1;
|
||||
|
||||
if(opt->wbout2.filename != NULL && (opt->extract != 2 || opt->extract != 12) )
|
||||
mprint("WARN: -o2 ignored! you might want -2 or -12 with -o2\n");
|
||||
|
||||
// Init telexcc redundant options
|
||||
tlt_config.transcript_settings = &opt->transcript_settings;
|
||||
tlt_config.levdistmincnt = opt->levdistmincnt;
|
||||
tlt_config.levdistmaxpct = opt->levdistmaxpct;
|
||||
tlt_config.extraction_start = opt->extraction_start;
|
||||
@@ -1683,7 +1712,6 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
tlt_config.date_format = opt->date_format;
|
||||
tlt_config.noautotimeref = opt->noautotimeref;
|
||||
tlt_config.send_to_srv = opt->send_to_srv;
|
||||
tlt_config.encoding = opt->encoding;
|
||||
tlt_config.nofontcolor = opt->nofontcolor;
|
||||
tlt_config.millis_separator = opt->millis_separator;
|
||||
|
||||
@@ -1717,17 +1745,55 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
return EXIT_TOO_MANY_INPUT_FILES;
|
||||
}
|
||||
|
||||
if (opt->demux_cfg.auto_stream == CCX_SM_MCPOODLESRAW && opt->write_format==CCX_OF_RAW)
|
||||
{
|
||||
print_error(opt->gui_mode_reports, "-in=raw can only be used if the output is a subtitle file.\n");
|
||||
return EXIT_INCOMPATIBLE_PARAMETERS;
|
||||
}
|
||||
if (opt->demux_cfg.auto_stream == CCX_SM_RCWT && opt->write_format==CCX_OF_RCWT && opt->output_filename == NULL)
|
||||
{
|
||||
print_error(opt->gui_mode_reports,
|
||||
"CCExtractor's binary format can only be used simultaneously for input and\noutput if the output file name is specified given with -o.\n");
|
||||
return EXIT_INCOMPATIBLE_PARAMETERS;
|
||||
}
|
||||
if (opt->write_format != CCX_OF_DVDRAW && opt->cc_to_stdout && opt->extract==12)
|
||||
{
|
||||
print_error(opt->gui_mode_reports, "You can't extract both fields to stdout at the same time in broadcast mode.");
|
||||
return EXIT_INCOMPATIBLE_PARAMETERS;
|
||||
}
|
||||
if (opt->write_format == CCX_OF_SPUPNG && opt->cc_to_stdout)
|
||||
{
|
||||
print_error(opt->gui_mode_reports, "You cannot use -out=spupng with -stdout.");
|
||||
return EXIT_INCOMPATIBLE_PARAMETERS;
|
||||
}
|
||||
|
||||
if (opt->write_format == CCX_OF_WEBVTT && opt->enc_cfg.encoding != CCX_ENC_UTF_8)
|
||||
{
|
||||
mprint("Note: Output format is WebVTT, forcing UTF-8");
|
||||
opt->enc_cfg.encoding = CCX_ENC_UTF_8;
|
||||
}
|
||||
|
||||
/* Initialize some Encoder Configuration */
|
||||
opt->enc_cfg.extract = opt->extract;
|
||||
if (opt->num_input_files > 0)
|
||||
{
|
||||
opt->enc_cfg.multiple_files = 1;
|
||||
opt->enc_cfg.first_input_file = opt->inputfile[0];
|
||||
}
|
||||
opt->enc_cfg.cc_to_stdout = opt->cc_to_stdout;
|
||||
opt->enc_cfg.write_format = opt->write_format;
|
||||
opt->enc_cfg.send_to_srv = opt->send_to_srv;
|
||||
opt->enc_cfg.date_format = opt->date_format;
|
||||
opt->enc_cfg.transcript_settings = opt->transcript_settings;
|
||||
opt->enc_cfg.millis_separator = opt->millis_separator;
|
||||
opt->enc_cfg.no_font_color = opt->nofontcolor;
|
||||
opt->enc_cfg.no_type_setting = opt->notypesetting;
|
||||
opt->enc_cfg.subs_delay = opt->subs_delay;
|
||||
if(opt->output_filename && opt->multiprogram == CCX_FALSE)
|
||||
opt->enc_cfg.output_filename = strdup(opt->output_filename);
|
||||
else
|
||||
opt->enc_cfg.output_filename = NULL;
|
||||
return EXIT_OK;
|
||||
|
||||
}
|
||||
|
||||
int detect_input_file_overwrite(struct lib_ccx_ctx *ctx, const char *output_filename)
|
||||
{
|
||||
for (int i = 0; i < ctx->num_input_files; i++)
|
||||
{
|
||||
if (!strcmp(ctx->inputfile[i], output_filename)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "teletext.h"
|
||||
|
||||
#include "ccx_decoders_708.h"
|
||||
|
||||
void params_dump(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
@@ -29,48 +32,12 @@ void params_dump(struct lib_ccx_ctx *ctx)
|
||||
mprint ("\n");
|
||||
mprint ("[Extract: %d] ", ccx_options.extract);
|
||||
mprint ("[Stream mode: ");
|
||||
switch (ctx->auto_stream)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
mprint ("Elementary");
|
||||
break;
|
||||
case CCX_SM_TRANSPORT:
|
||||
mprint ("Transport");
|
||||
break;
|
||||
case CCX_SM_PROGRAM:
|
||||
mprint ("Program");
|
||||
break;
|
||||
case CCX_SM_ASF:
|
||||
mprint ("DVR-MS");
|
||||
break;
|
||||
case CCX_SM_WTV:
|
||||
mprint ("Windows Television (WTV)");
|
||||
break;
|
||||
case CCX_SM_MCPOODLESRAW:
|
||||
mprint ("McPoodle's raw");
|
||||
break;
|
||||
case CCX_SM_AUTODETECT:
|
||||
mprint ("Autodetect");
|
||||
break;
|
||||
case CCX_SM_RCWT:
|
||||
mprint ("BIN");
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
mprint ("MP4");
|
||||
break;
|
||||
#ifdef WTV_DEBUG
|
||||
case CCX_SM_HEX_DUMP:
|
||||
mprint ("Hex");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "BUG: Unknown stream mode.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->demux_ctx->print_cfg(ctx->demux_ctx);
|
||||
mprint ("]\n");
|
||||
mprint ("[Program : ");
|
||||
if (ccx_options.ts_forced_program_selected != 0)
|
||||
mprint ("%u ]",ccx_options.ts_forced_program);
|
||||
if (ccx_options.demux_cfg.ts_forced_program_selected != 0)
|
||||
mprint ("%u ]",ccx_options.demux_cfg.ts_forced_program);
|
||||
else
|
||||
mprint ("Auto ]");
|
||||
mprint (" [Hauppage mode: %s]",ccx_options.hauppauge_mode?"Yes":"No");
|
||||
@@ -89,17 +56,34 @@ void params_dump(struct lib_ccx_ctx *ctx)
|
||||
break;
|
||||
}
|
||||
mprint ("]");
|
||||
if (ccx_options.wtvconvertfix)
|
||||
{
|
||||
mprint (" [Windows 7 wtv to dvr-ms conversion fix: Enabled]");
|
||||
}
|
||||
mprint ("\n");
|
||||
|
||||
if (ccx_options.wtvmpeg2)
|
||||
if (ccx_options.settings_dtvcc.enabled)
|
||||
{
|
||||
mprint (" [WTV use MPEG2 stream: Enabled]");
|
||||
mprint ("[CEA-708: %d decoders active]\n", ccx_options.settings_dtvcc.active_services_count);
|
||||
if (ccx_options.settings_dtvcc.active_services_count == CCX_DTVCC_MAX_SERVICES)
|
||||
{
|
||||
char *charset = ccx_options.enc_cfg.all_services_charset;
|
||||
mprint ("[CEA-708: using charset \"%s\" for all services]\n", charset ? charset : "none");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
|
||||
{
|
||||
if (ccx_options.settings_dtvcc.services_enabled[i])
|
||||
mprint("[CEA-708: using charset \"%s\" for service %d]\n",
|
||||
ccx_options.enc_cfg.services_charsets[i] ?
|
||||
ccx_options.enc_cfg.services_charsets[i] : "none",
|
||||
i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
mprint ("\n");
|
||||
|
||||
if (ccx_options.wtvconvertfix)
|
||||
mprint (" [Windows 7 wtv to dvr-ms conversion fix: Enabled]\n");
|
||||
|
||||
if (ccx_options.wtvmpeg2)
|
||||
mprint (" [WTV use MPEG2 stream: Enabled]\n");
|
||||
|
||||
mprint ("[Timing mode: ");
|
||||
switch (ccx_options.use_gop_as_pts)
|
||||
@@ -121,7 +105,7 @@ void params_dump(struct lib_ccx_ctx *ctx)
|
||||
mprint("[Print CC decoder traces: %s]\n", (ccx_options.debug_mask & CCX_DMT_DECODER_608) ? "Yes" : "No");
|
||||
mprint ("[Target format: %s] ",ctx->extension);
|
||||
mprint ("[Encoding: ");
|
||||
switch (ccx_options.encoding)
|
||||
switch (ccx_options.enc_cfg.encoding)
|
||||
{
|
||||
case CCX_ENC_UNICODE:
|
||||
mprint ("Unicode");
|
||||
@@ -136,7 +120,7 @@ void params_dump(struct lib_ccx_ctx *ctx)
|
||||
mprint ("] ");
|
||||
mprint ("[Delay: %lld] ",ctx->subs_delay);
|
||||
|
||||
mprint ("[Trim lines: %s]\n",ccx_options.trim_subs?"Yes":"No");
|
||||
mprint ("[Trim lines: %s]\n",ccx_options.enc_cfg.trim_subs?"Yes":"No");
|
||||
mprint ("[Add font color data: %s] ", ccx_options.nofontcolor? "No" : "Yes");
|
||||
mprint ("[Add font typesetting: %s]\n", ccx_options.notypesetting? "No" : "Yes");
|
||||
mprint ("[Convert case: ");
|
||||
@@ -144,7 +128,7 @@ void params_dump(struct lib_ccx_ctx *ctx)
|
||||
mprint ("Yes, using %s", ccx_options.sentence_cap_file);
|
||||
else
|
||||
{
|
||||
mprint ("%s",ccx_options.sentence_cap?"Yes, but only built-in words":"No");
|
||||
mprint ("%s",ccx_options.enc_cfg.sentence_cap?"Yes, but only built-in words":"No");
|
||||
}
|
||||
mprint ("]");
|
||||
mprint (" [Video-edit join: %s]", ccx_options.binary_concat?"No":"Yes");
|
||||
@@ -175,41 +159,75 @@ void params_dump(struct lib_ccx_ctx *ctx)
|
||||
mprint ("Yes, timeout: %d seconds",ccx_options.live_stream);
|
||||
}
|
||||
mprint ("] [Clock frequency: %d]\n",MPEG_CLOCK_FREQ);
|
||||
mprint ("Teletext page: [");
|
||||
mprint ("[Teletext page: ");
|
||||
if (tlt_config.page)
|
||||
mprint ("%d]\n",tlt_config.page);
|
||||
else
|
||||
mprint ("Autodetect]\n");
|
||||
mprint ("Start credits text: [%s]\n",
|
||||
ccx_options.start_credits_text?ccx_options.start_credits_text:"None");
|
||||
if (ccx_options.start_credits_text)
|
||||
mprint ("[Start credits text: %s]\n",
|
||||
ccx_options.enc_cfg.start_credits_text?ccx_options.enc_cfg.start_credits_text:"None");
|
||||
if (ccx_options.enc_cfg.start_credits_text)
|
||||
{
|
||||
mprint ("Start credits time: Insert between [%ld] and [%ld] seconds\n",
|
||||
(long) (ccx_options.startcreditsnotbefore.time_in_ms/1000),
|
||||
(long) (ccx_options.startcreditsnotafter.time_in_ms/1000)
|
||||
(long) (ccx_options.enc_cfg.startcreditsnotbefore.time_in_ms/1000),
|
||||
(long) (ccx_options.enc_cfg.startcreditsnotafter.time_in_ms/1000)
|
||||
);
|
||||
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
|
||||
(long) (ccx_options.startcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.startcreditsforatmost.time_in_ms/1000)
|
||||
(long) (ccx_options.enc_cfg.startcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.enc_cfg.startcreditsforatmost.time_in_ms/1000)
|
||||
);
|
||||
}
|
||||
if (ccx_options.end_credits_text)
|
||||
if (ccx_options.enc_cfg.end_credits_text)
|
||||
{
|
||||
mprint ("End credits text: [%s]\n",
|
||||
ccx_options.end_credits_text?ccx_options.end_credits_text:"None");
|
||||
ccx_options.enc_cfg.end_credits_text?ccx_options.enc_cfg.end_credits_text:"None");
|
||||
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
|
||||
(long) (ccx_options.endcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.endcreditsforatmost.time_in_ms/1000)
|
||||
(long) (ccx_options.enc_cfg.endcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.enc_cfg.endcreditsforatmost.time_in_ms/1000)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define Y_N(cond) ((cond) ? "Yes" : "No")
|
||||
|
||||
void print_cc_report(struct lib_ccx_ctx *ctx, struct cap_info* info)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = update_decoder_list_cinfo(ctx, info);
|
||||
printf("EIA-608: %s\n", Y_N(dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0));
|
||||
|
||||
if (dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0)
|
||||
{
|
||||
printf("XDS: %s\n", Y_N(ctx->freport.data_from_608->xds));
|
||||
|
||||
printf("CC1: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[0]));
|
||||
printf("CC2: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[1]));
|
||||
printf("CC3: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[2]));
|
||||
printf("CC4: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[3]));
|
||||
}
|
||||
printf("CEA-708: %s\n", Y_N(dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0));
|
||||
|
||||
if (dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0)
|
||||
{
|
||||
printf("Services: ");
|
||||
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
|
||||
{
|
||||
if (ctx->freport.data_from_708->services[i] == 0)
|
||||
continue;
|
||||
printf("%d ", i);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Primary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[1]));
|
||||
|
||||
printf("Secondary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[2]));
|
||||
}
|
||||
}
|
||||
void print_file_report(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
#define Y_N(cond) ((cond) ? "Yes" : "No")
|
||||
enum ccx_stream_mode_enum stream_mode;
|
||||
struct ccx_demuxer *demux_ctx = ctx->demux_ctx;
|
||||
|
||||
printf("File: ");
|
||||
switch (ccx_options.input_source)
|
||||
@@ -232,46 +250,44 @@ void print_file_report(struct lib_ccx_ctx *ctx)
|
||||
break;
|
||||
}
|
||||
|
||||
struct cap_info* program;
|
||||
printf("Stream Mode: ");
|
||||
switch (ctx->stream_mode)
|
||||
switch (demux_ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_TRANSPORT:
|
||||
printf("Transport Stream\n");
|
||||
|
||||
printf("Program Count: %d\n", ctx->freport.program_cnt);
|
||||
printf("Program Count: %d\n", demux_ctx->freport.program_cnt);
|
||||
|
||||
printf("Program Numbers: ");
|
||||
for (int i = 0; i < pmt_array_length; i++)
|
||||
{
|
||||
if (pmt_array[i].program_number == 0)
|
||||
continue;
|
||||
|
||||
printf("%u ", pmt_array[i].program_number);
|
||||
}
|
||||
for (int i = 0; i < demux_ctx->nb_program; i++)
|
||||
printf("%u ", demux_ctx->pinfo[i].program_number);
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < 65536; i++)
|
||||
{
|
||||
if (ctx->PIDs_programs[i] == 0)
|
||||
if (demux_ctx->PIDs_programs[i] == 0)
|
||||
continue;
|
||||
|
||||
printf("PID: %u, Program: %u, ", i, ctx->PIDs_programs[i]->program_number);
|
||||
printf("PID: %u, Program: %u, ", i, demux_ctx->PIDs_programs[i]->program_number);
|
||||
int j;
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
{
|
||||
if (ctx->freport.dvb_sub_pid[j] == i)
|
||||
if (demux_ctx->freport.dvb_sub_pid[j] == i)
|
||||
{
|
||||
printf("DVB Subtitles\n");
|
||||
break;
|
||||
}
|
||||
if (ctx->freport.tlt_sub_pid[j] == i)
|
||||
if (demux_ctx->freport.tlt_sub_pid[j] == i)
|
||||
{
|
||||
printf("Teletext Subtitles\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == SUB_STREAMS_CNT)
|
||||
printf("%s\n", desc[ctx->PIDs_programs[i]->printable_stream_type]);
|
||||
printf("%s\n", desc[demux_ctx->PIDs_programs[i]->printable_stream_type]);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -304,91 +320,65 @@ void print_file_report(struct lib_ccx_ctx *ctx)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ccx_bufferdatatype == CCX_PES &&
|
||||
(ctx->stream_mode == CCX_SM_TRANSPORT ||
|
||||
ctx->stream_mode == CCX_SM_PROGRAM ||
|
||||
ctx->stream_mode == CCX_SM_ASF ||
|
||||
ctx->stream_mode == CCX_SM_WTV))
|
||||
if(list_empty(&demux_ctx->cinfo_tree.all_stream))
|
||||
{
|
||||
printf("Width: %u\n", ctx->freport.width);
|
||||
printf("Height: %u\n", ctx->freport.height);
|
||||
printf("Aspect Ratio: %s\n", aspect_ratio_types[ctx->freport.aspect_ratio]);
|
||||
printf("Frame Rate: %s\n", framerates_types[ctx->freport.frame_rate]);
|
||||
print_cc_report(ctx, NULL);
|
||||
}
|
||||
|
||||
if (ctx->freport.program_cnt > 1)
|
||||
printf("//////// Program #%u: ////////\n", TS_program_number);
|
||||
|
||||
printf("DVB Subtitles: ");
|
||||
int j;
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
list_for_each_entry(program, &demux_ctx->cinfo_tree.pg_stream, pg_stream, struct cap_info)
|
||||
{
|
||||
unsigned pid = ctx->freport.dvb_sub_pid[j];
|
||||
if (pid == 0)
|
||||
continue;
|
||||
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
|
||||
struct cap_info* info = NULL;
|
||||
printf("//////// Program #%u: ////////\n", program->program_number);
|
||||
|
||||
printf("DVB Subtitles: ");
|
||||
info = get_sib_stream_by_type(program, CCX_CODEC_DVB);
|
||||
if(info)
|
||||
printf("Yes\n");
|
||||
else
|
||||
printf("No\n");
|
||||
|
||||
printf("Teletext: ");
|
||||
info = get_sib_stream_by_type(program, CCX_CODEC_TELETEXT);
|
||||
if(info)
|
||||
{
|
||||
printf("Yes\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == SUB_STREAMS_CNT)
|
||||
printf("No\n");
|
||||
|
||||
printf("Teletext: ");
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
{
|
||||
unsigned pid = ctx->freport.tlt_sub_pid[j];
|
||||
if (pid == 0)
|
||||
continue;
|
||||
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
|
||||
{
|
||||
printf("Yes\n");
|
||||
|
||||
dec_ctx = update_decoder_list_cinfo(ctx, info);
|
||||
printf("Pages With Subtitles: ");
|
||||
for (int i = 0; i < MAX_TLT_PAGES; i++)
|
||||
{
|
||||
if (seen_sub_page[i] == 0)
|
||||
continue;
|
||||
tlt_print_seen_pages(dec_ctx);
|
||||
|
||||
printf("%d ", i);
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (j == SUB_STREAMS_CNT)
|
||||
printf("No\n");
|
||||
else
|
||||
printf("No\n");
|
||||
|
||||
printf("EIA-608: %s\n", Y_N(dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0));
|
||||
|
||||
if (dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0)
|
||||
{
|
||||
printf("XDS: %s\n", Y_N(ctx->freport.data_from_608->xds));
|
||||
|
||||
printf("CC1: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[0]));
|
||||
printf("CC2: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[1]));
|
||||
printf("CC3: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[2]));
|
||||
printf("CC4: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[3]));
|
||||
}
|
||||
|
||||
printf("CEA-708: %s\n", Y_N(dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0));
|
||||
|
||||
if (dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0)
|
||||
{
|
||||
printf("Services: ");
|
||||
for (int i = 0; i < CCX_DECODERS_708_MAX_SERVICES; i++)
|
||||
printf("ATSC Closed Caption: ");
|
||||
info = get_sib_stream_by_type(program, CCX_CODEC_ATSC_CC);
|
||||
if(info)
|
||||
{
|
||||
if (ctx->freport.data_from_708->services[i] == 0)
|
||||
continue;
|
||||
printf("%d ", i);
|
||||
printf("Yes\n");
|
||||
print_cc_report(ctx, info);
|
||||
}
|
||||
else
|
||||
printf("No\n");
|
||||
|
||||
|
||||
info = get_best_sib_stream(program);
|
||||
if(!info)
|
||||
continue;
|
||||
|
||||
dec_ctx = update_decoder_list_cinfo(ctx, info);
|
||||
if (dec_ctx->in_bufferdatatype == CCX_PES &&
|
||||
(info->stream == CCX_SM_TRANSPORT ||
|
||||
info->stream == CCX_SM_PROGRAM ||
|
||||
info->stream == CCX_SM_ASF ||
|
||||
info->stream == CCX_SM_WTV))
|
||||
{
|
||||
printf("Width: %u\n", dec_ctx->current_hor_size);
|
||||
printf("Height: %u\n", dec_ctx->current_vert_size);
|
||||
printf("Aspect Ratio: %s\n", aspect_ratio_types[dec_ctx->current_aspect_ratio]);
|
||||
printf("Frame Rate: %s\n", framerates_types[dec_ctx->current_frame_rate]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Primary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[1]));
|
||||
|
||||
printf("Secondary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[2]));
|
||||
}
|
||||
|
||||
printf("MPEG-4 Timed Text: %s\n", Y_N(ctx->freport.mp4_cc_track_cnt));
|
||||
@@ -396,7 +386,7 @@ void print_file_report(struct lib_ccx_ctx *ctx)
|
||||
printf("MPEG-4 Timed Text tracks count: %d\n", ctx->freport.mp4_cc_track_cnt);
|
||||
}
|
||||
|
||||
freep(&ctx->freport.data_from_608);
|
||||
memset(&ctx->freport, 0, sizeof (struct file_report));
|
||||
|
||||
#undef Y_N
|
||||
}
|
||||
|
||||
@@ -7,39 +7,31 @@
|
||||
// enough space.
|
||||
//#define SORTBUF (2*MAXBFRAMES+1) - from lib_ccx.h
|
||||
// B-Frames can be (temporally) before or after the anchor
|
||||
int cc_data_count[SORTBUF];
|
||||
// Store fts;
|
||||
static LLONG cc_fts[SORTBUF];
|
||||
// Store HD CC packets
|
||||
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
|
||||
|
||||
// Set to true if data is buffered
|
||||
int has_ccdata_buffered = 0;
|
||||
// The sequence number of the current anchor frame. All currently read
|
||||
// B-Frames belong to this I- or P-frame.
|
||||
static int anchor_seq_number = -1;
|
||||
|
||||
void init_hdcc (void)
|
||||
void init_hdcc (struct lib_cc_decode *ctx)
|
||||
{
|
||||
for (int j=0; j<SORTBUF; j++)
|
||||
{
|
||||
cc_data_count[j] = 0;
|
||||
cc_fts[j] = 0;
|
||||
ctx->cc_data_count[j] = 0;
|
||||
ctx->cc_fts[j] = 0;
|
||||
}
|
||||
memset(cc_data_pkts, 0, SORTBUF*(31*3+1));
|
||||
has_ccdata_buffered = 0;
|
||||
memset(ctx->cc_data_pkts, 0, SORTBUF*(31*3+1));
|
||||
ctx->has_ccdata_buffered = 0;
|
||||
}
|
||||
|
||||
// Buffer caption blocks for later sorting/flushing.
|
||||
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now,struct cc_subtitle *sub)
|
||||
void store_hdcc(struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now, struct cc_subtitle *sub)
|
||||
{
|
||||
enum ccx_stream_mode_enum stream_mode;
|
||||
|
||||
//stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx);
|
||||
// Uninitialized?
|
||||
if (anchor_seq_number < 0)
|
||||
if (ctx->anchor_seq_number < 0)
|
||||
{
|
||||
anchor_hdcc( sequence_number);
|
||||
anchor_hdcc( ctx, sequence_number);
|
||||
}
|
||||
|
||||
int seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
|
||||
int seq_index = sequence_number - ctx->anchor_seq_number + MAXBFRAMES;
|
||||
|
||||
if (seq_index < 0 || seq_index > 2*MAXBFRAMES)
|
||||
{
|
||||
@@ -47,11 +39,11 @@ void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, i
|
||||
dbg_print(CCX_DMT_VERBOSE, "Too many B-frames, or missing anchor frame. Trying to recover ..\n");
|
||||
|
||||
process_hdcc(ctx, sub);
|
||||
anchor_hdcc( sequence_number);
|
||||
seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
|
||||
anchor_hdcc( ctx, sequence_number);
|
||||
seq_index = sequence_number - ctx->anchor_seq_number + MAXBFRAMES;
|
||||
}
|
||||
|
||||
has_ccdata_buffered = 1;
|
||||
ctx->has_ccdata_buffered = 1;
|
||||
|
||||
// In GOP mode the fts is set only once for the whole GOP. Recreate
|
||||
// the right time according to the sequence number.
|
||||
@@ -66,12 +58,12 @@ void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, i
|
||||
{
|
||||
// Changed by CFS to concat, i.e. don't assume there's no data already for this seq_index.
|
||||
// Needed at least for MP4 samples. // TODO: make sure we don't overflow
|
||||
cc_fts[seq_index] = current_fts_now; // CFS: Maybe do even if there's no data?
|
||||
if (ctx->stream_mode!=CCX_SM_MP4) // CFS: Very ugly hack, but looks like overwriting is needed for at least some ES
|
||||
cc_data_count[seq_index] = 0;
|
||||
memcpy(cc_data_pkts[seq_index] + cc_data_count[seq_index] * 3, cc_data, cc_count * 3 + 1);
|
||||
ctx->cc_fts[seq_index] = current_fts_now; // CFS: Maybe do even if there's no data?
|
||||
//if (stream_mode!=CCX_SM_MP4) // CFS: Very ugly hack, but looks like overwriting is needed for at least some ES
|
||||
ctx->cc_data_count[seq_index] = 0;
|
||||
memcpy(ctx->cc_data_pkts[seq_index] + ctx->cc_data_count[seq_index] * 3, cc_data, cc_count * 3 + 1);
|
||||
}
|
||||
cc_data_count[seq_index] += cc_count;
|
||||
ctx->cc_data_count[seq_index] += cc_count;
|
||||
}
|
||||
// DEBUG STUFF
|
||||
/*
|
||||
@@ -85,28 +77,27 @@ void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, i
|
||||
}
|
||||
|
||||
// Set a new anchor frame that new B-frames refer to.
|
||||
void anchor_hdcc(int seq)
|
||||
void anchor_hdcc(struct lib_cc_decode *ctx, int seq)
|
||||
{
|
||||
// Re-init the index
|
||||
anchor_seq_number = seq;
|
||||
ctx->anchor_seq_number = seq;
|
||||
}
|
||||
|
||||
// Sort/flash caption block buffer
|
||||
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
void process_hdcc (struct lib_cc_decode *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
// Remember the current value
|
||||
LLONG store_fts_now = fts_now;
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
LLONG store_fts_now = ctx->timing->fts_now;
|
||||
int reset_cb = -1;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Flush HD caption blocks\n");
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
|
||||
for (int seq=0; seq<SORTBUF; seq++)
|
||||
{
|
||||
|
||||
// We rely on this.
|
||||
if (ccx_bufferdatatype == CCX_H264)
|
||||
reset_cb = 1;
|
||||
if (ctx->in_bufferdatatype == CCX_H264)
|
||||
reset_cb = 1;
|
||||
|
||||
// If fts_now is unchanged we rely on cc block counting,
|
||||
// otherwise reset counters as they get changed by do_cb()
|
||||
@@ -114,9 +105,9 @@ void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
// updated, like it used do happen for elementary streams.
|
||||
// Since use_gop_as_pts this is not needed anymore, but left
|
||||
// here for posterity.
|
||||
if (reset_cb < 0 && cc_fts[seq] && seq<SORTBUF-1 && cc_fts[seq+1])
|
||||
if (reset_cb < 0 && ctx->cc_fts[seq] && seq<SORTBUF-1 && ctx->cc_fts[seq+1])
|
||||
{
|
||||
if (cc_fts[seq] != cc_fts[seq+1])
|
||||
if (ctx->cc_fts[seq] != ctx->cc_fts[seq+1])
|
||||
reset_cb = 1;
|
||||
else
|
||||
reset_cb = 0;
|
||||
@@ -129,10 +120,10 @@ void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
}
|
||||
|
||||
// Skip sequence numbers without data
|
||||
if (cc_data_count[seq] == 0)
|
||||
if (ctx->cc_data_count[seq] == 0)
|
||||
continue;
|
||||
|
||||
if (cc_data_pkts[seq][cc_data_count[seq]*3]!=0xFF)
|
||||
if (ctx->cc_data_pkts[seq][ctx->cc_data_count[seq]*3]!=0xFF)
|
||||
{
|
||||
// This is not optional. Something is wrong.
|
||||
dbg_print(CCX_DMT_VERBOSE, "Missing 0xFF marker at end\n");
|
||||
@@ -141,14 +132,14 @@ void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
}
|
||||
|
||||
// Re-create original time
|
||||
fts_now = cc_fts[seq];
|
||||
process_cc_data( dec_ctx, cc_data_pkts[seq], cc_data_count[seq], sub);
|
||||
ctx->timing->fts_now = ctx->cc_fts[seq];
|
||||
process_cc_data( ctx, ctx->cc_data_pkts[seq], ctx->cc_data_count[seq], sub);
|
||||
|
||||
}
|
||||
|
||||
// Restore the value
|
||||
fts_now = store_fts_now;
|
||||
ctx->timing->fts_now = store_fts_now;
|
||||
|
||||
// Now that we are done, clean up.
|
||||
init_hdcc();
|
||||
init_hdcc(ctx);
|
||||
}
|
||||
|
||||
@@ -109,12 +109,12 @@ void spupng_write_footer(struct spupng_t *sp)
|
||||
fclose(sp->fpxml);
|
||||
}
|
||||
|
||||
void write_spumux_header(struct ccx_s_write *out)
|
||||
void write_spumux_header(struct encoder_ctx *ctx, struct ccx_s_write *out)
|
||||
{
|
||||
if (0 == out->spupng_data)
|
||||
out->spupng_data = spunpg_init(out);
|
||||
|
||||
spupng_write_header((struct spupng_t*)out->spupng_data,out->multiple_files,out->first_input_file);
|
||||
spupng_write_header((struct spupng_t*)out->spupng_data, ctx->multiple_files, ctx->first_input_file);
|
||||
}
|
||||
|
||||
void write_spumux_footer(struct ccx_s_write *out)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_encoders_structs.h"
|
||||
#include "png.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
|
||||
// CC page dimensions
|
||||
#define ROWS 15
|
||||
@@ -23,7 +24,7 @@ struct spupng_t
|
||||
int yOffset;
|
||||
};
|
||||
|
||||
void write_spumux_header(struct ccx_s_write *out);
|
||||
void write_spumux_header(struct encoder_ctx *ctx, struct ccx_s_write *out);
|
||||
void write_spumux_footer(struct ccx_s_write *out);
|
||||
void draw_char_indexed(uint8_t * canvas, int rowstride, uint8_t * pen,
|
||||
int unicode, int italic, int underline);
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "activity.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_common_timing.h"
|
||||
#include "file_buffer.h"
|
||||
|
||||
void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
void detect_stream_type (struct ccx_demuxer *ctx)
|
||||
{
|
||||
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
|
||||
ctx->startbytes_avail = (int) buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
|
||||
@@ -66,7 +70,7 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
while (idx < ctx->startbytes_avail - 7){
|
||||
lastBoxLocation = idx;
|
||||
// Check if we have a valid box
|
||||
if (isValidMP4Box(&ctx->startbytes, idx, &nextBoxLocation, &boxScore))
|
||||
if (isValidMP4Box(ctx->startbytes, idx, &nextBoxLocation, &boxScore))
|
||||
{
|
||||
idx = nextBoxLocation; // If the box is valid, a new box should be found on the next location... Not somewhere in between.
|
||||
if (boxScore > 7)
|
||||
@@ -111,7 +115,7 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
if (ctx->stream_mode == CCX_SM_TRANSPORT)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as TS\n");
|
||||
return_to_buffer (ctx->startbytes, (unsigned int)ctx->startbytes_avail);
|
||||
return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,7 +138,7 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
if (ctx->stream_mode == CCX_SM_TRANSPORT)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as M2TS\n");
|
||||
return_to_buffer (ctx->startbytes, (unsigned int)ctx->startbytes_avail);
|
||||
return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -163,9 +167,9 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
// The TiVo header is longer, but the PS loop will find the beginning
|
||||
dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as Tivo PS\n");
|
||||
ctx->startbytes_pos=187;
|
||||
ctx->stream_mode=CCX_SM_PROGRAM;
|
||||
strangeheader=1; // Avoid message about unrecognized header
|
||||
ctx->startbytes_pos = 187;
|
||||
ctx->stream_mode = CCX_SM_PROGRAM;
|
||||
ctx->strangeheader = 1; // Avoid message about unrecognized header
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -175,11 +179,11 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
}
|
||||
}
|
||||
// Don't use STARTBYTESLENGTH. It might be longer than the file length!
|
||||
return_to_buffer (ctx->startbytes, ctx->startbytes_avail);
|
||||
return_to_buffer (ctx, ctx->startbytes, ctx->startbytes_avail);
|
||||
}
|
||||
|
||||
|
||||
int detect_myth( struct lib_ccx_ctx *ctx )
|
||||
int detect_myth( struct ccx_demuxer *ctx )
|
||||
{
|
||||
int vbi_blocks=0;
|
||||
// VBI data? if yes, use myth loop
|
||||
@@ -204,40 +208,6 @@ int detect_myth( struct lib_ccx_ctx *ctx )
|
||||
|
||||
return 0;
|
||||
}
|
||||
int read_pts_pes(unsigned char*header, int len)
|
||||
{
|
||||
/* unsigned int peslen = 0; */
|
||||
LLONG bits_9;
|
||||
unsigned int bits_10;
|
||||
unsigned int bits_11;
|
||||
unsigned int bits_12;
|
||||
unsigned int bits_13;
|
||||
|
||||
//function used only to set start time
|
||||
if(pts_set)
|
||||
return -1;
|
||||
//it might not be pes packet
|
||||
if (!(header[0] == 0 && header[1] == 0 && header[2] == 1))
|
||||
return -1;
|
||||
|
||||
|
||||
/* peslen = header[4] << 8 | header[5]; */
|
||||
|
||||
if (header[7] & 0x80)
|
||||
{
|
||||
bits_9 = ((LLONG) header[9] & 0x0E) << 29; // PTS 32..30 - Must be LLONG to prevent overflow
|
||||
bits_10 = header[10] << 22; // PTS 29..22
|
||||
bits_11 = (header[11] & 0xFE) << 14; // PTS 21..15
|
||||
bits_12 = header[12] << 7; // PTS 14-7
|
||||
bits_13 = header[13] >> 1; // PTS 6-0
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
current_pts = bits_9 | bits_10 | bits_11 | bits_12 | bits_13;
|
||||
pts_set = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read and evaluate the current video PES header. The function returns
|
||||
* the length of the payload if successful, otherwise -1 is returned
|
||||
@@ -246,10 +216,11 @@ int read_pts_pes(unsigned char*header, int len)
|
||||
* 0 .. Read from file into nextheader
|
||||
* >0 .. Use data in nextheader with the length of sbuflen
|
||||
*/
|
||||
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen)
|
||||
int read_video_pes_header (struct ccx_demuxer *ctx, struct demuxer_data *data, unsigned char *nextheader, int *headerlength, int sbuflen)
|
||||
{
|
||||
// Read the next video PES
|
||||
// ((nextheader[3]&0xf0)==0xe0)
|
||||
long long result;
|
||||
unsigned peslen=nextheader[4]<<8 | nextheader[5];
|
||||
unsigned payloadlength = 0; // Length of packet data bytes
|
||||
static LLONG current_pts_33=0; // Last PTS from the header, without rollover bits
|
||||
@@ -257,7 +228,7 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
|
||||
if ( !sbuflen )
|
||||
{
|
||||
// Extension present, get it
|
||||
buffered_read (ctx, nextheader+6,3);
|
||||
result = buffered_read (ctx, nextheader+6,3);
|
||||
ctx->past=ctx->past+result;
|
||||
if (result!=3) {
|
||||
// Consider this the end of the show.
|
||||
@@ -266,13 +237,12 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ccx_bufferdatatype == CCX_DVB_SUBTITLE
|
||||
if (data->bufferdatatype == CCX_DVB_SUBTITLE
|
||||
&& peslen == 1 && nextheader[6] == 0xFF)
|
||||
{
|
||||
*headerlength = sbuflen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sbuflen < 9) // We need at least 9 bytes to continue
|
||||
{
|
||||
return -1;
|
||||
@@ -287,8 +257,8 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
|
||||
{
|
||||
if (nextheader[8] > 0)
|
||||
{
|
||||
buffered_read (ctx, nextheader+9,nextheader[8]);
|
||||
ctx->past=ctx->past+result;
|
||||
result = buffered_read (ctx, nextheader+9,nextheader[8]);
|
||||
ctx->past = ctx->past+result;
|
||||
if (result!=nextheader[8])
|
||||
{
|
||||
return -1;
|
||||
@@ -391,7 +361,7 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
|
||||
unsigned bits_12 = nextheader[12] << 7; // PTS 14-7
|
||||
unsigned bits_13 = nextheader[13] >> 1; // PTS 6-0
|
||||
|
||||
if (pts_set) // Otherwise can't check for rollovers yet
|
||||
if (data->pts != CCX_NOPTS) // Otherwise can't check for rollovers yet
|
||||
{
|
||||
if (!bits_9 && ((current_pts_33>>30)&7)==7) // PTS about to rollover
|
||||
rollover_bits++;
|
||||
@@ -401,14 +371,8 @@ int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, i
|
||||
|
||||
|
||||
current_pts_33 = bits_9 | bits_10 | bits_11 | bits_12 | bits_13;
|
||||
current_pts = (LLONG) rollover_bits<<33 | current_pts_33;
|
||||
data->pts = (LLONG) rollover_bits<<33 | current_pts_33;
|
||||
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Set PTS: %s (%u)\n",
|
||||
print_mstime((current_pts)/(MPEG_CLOCK_FREQ/1000)),
|
||||
(unsigned) (current_pts) );
|
||||
/* The user data holding the captions seems to come between GOP and
|
||||
* the first frame. The sync PTS (sync_pts) (set at picture 0)
|
||||
* corresponds to the first frame of the current GOP. */
|
||||
|
||||
@@ -7,247 +7,6 @@
|
||||
|
||||
//#include <inttypes.h>
|
||||
|
||||
typedef enum {
|
||||
LATIN = 0,
|
||||
CYRILLIC1,
|
||||
CYRILLIC2,
|
||||
CYRILLIC3,
|
||||
GREEK,
|
||||
ARABIC,
|
||||
HEBREW
|
||||
} g0_charsets_t;
|
||||
|
||||
// Note: All characters are encoded in UCS-2
|
||||
|
||||
// --- G0 ----------------------------------------------------------------------
|
||||
|
||||
// G0 charsets
|
||||
uint16_t G0[5][96] = {
|
||||
{ // Latin G0 Primary Set
|
||||
0x0020, 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00ab, 0x00bd, 0x00bb, 0x005e, 0x0023,
|
||||
0x002d, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00bc, 0x00a6, 0x00be, 0x00f7, 0x007f
|
||||
},
|
||||
{ // Cyrillic G0 Primary Set - Option 1 - Serbian/Croatian
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x044b, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x3200, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
|
||||
0x041f, 0x040c, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040a, 0x0417, 0x040b, 0x0416, 0x0402, 0x0428, 0x040f,
|
||||
0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0428, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
|
||||
0x043f, 0x042c, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0423, 0x0429, 0x042a, 0x0437, 0x042b, 0x0436, 0x0422, 0x0448, 0x042f
|
||||
},
|
||||
{ // Cyrillic G0 Primary Set - Option 2 - Russian/Bulgarian
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x044b, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
|
||||
0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x042a, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042b,
|
||||
0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
|
||||
0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c, 0x044a, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044b
|
||||
},
|
||||
{ // Cyrillic G0 Primary Set - Option 3 - Ukrainian
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x00ef, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
|
||||
0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x0049, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x00cf,
|
||||
0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
|
||||
0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c, 0x0069, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x00ff
|
||||
},
|
||||
{ // Greek G0 Primary Set
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
|
||||
0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
|
||||
0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
|
||||
0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf
|
||||
}
|
||||
//{ // Arabic G0 Primary Set
|
||||
//},
|
||||
//{ // Hebrew G0 Primary Set
|
||||
//}
|
||||
};
|
||||
|
||||
// array positions where chars from G0_LATIN_NATIONAL_SUBSETS are injected into G0[LATIN]
|
||||
const uint8_t G0_LATIN_NATIONAL_SUBSETS_POSITIONS[13] = {
|
||||
0x03, 0x04, 0x20, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x5b, 0x5c, 0x5d, 0x5e
|
||||
};
|
||||
|
||||
// ETS 300 706, chapter 15.2, table 32: Function of Default G0 and G2 Character Set Designation
|
||||
// and National Option Selection bits in packets X/28/0 Format 1, X/28/4, M/29/0 and M/29/4
|
||||
|
||||
// Latin National Option Sub-sets
|
||||
struct {
|
||||
const char *language;
|
||||
uint16_t characters[13];
|
||||
} const G0_LATIN_NATIONAL_SUBSETS[14] = {
|
||||
{ // 0
|
||||
"English",
|
||||
{ 0x00a3, 0x0024, 0x0040, 0x00ab, 0x00bd, 0x00bb, 0x005e, 0x0023, 0x002d, 0x00bc, 0x00a6, 0x00be, 0x00f7 }
|
||||
},
|
||||
{ // 1
|
||||
"French",
|
||||
{ 0x00e9, 0x00ef, 0x00e0, 0x00eb, 0x00ea, 0x00f9, 0x00ee, 0x0023, 0x00e8, 0x00e2, 0x00f4, 0x00fb, 0x00e7 }
|
||||
},
|
||||
{ // 2
|
||||
"Swedish, Finnish, Hungarian",
|
||||
{ 0x0023, 0x00a4, 0x00c9, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f, 0x00e9, 0x00e4, 0x00f6, 0x00e5, 0x00fc }
|
||||
},
|
||||
{ // 3
|
||||
"Czech, Slovak",
|
||||
{ 0x0023, 0x016f, 0x010d, 0x0165, 0x017e, 0x00fd, 0x00ed, 0x0159, 0x00e9, 0x00e1, 0x011b, 0x00fa, 0x0161 }
|
||||
},
|
||||
{ // 4
|
||||
"German",
|
||||
{ 0x0023, 0x0024, 0x00a7, 0x00c4, 0x00d6, 0x00dc, 0x005e, 0x005f, 0x00b0, 0x00e4, 0x00f6, 0x00fc, 0x00df }
|
||||
},
|
||||
{ // 5
|
||||
"Portuguese, Spanish",
|
||||
{ 0x00e7, 0x0024, 0x00a1, 0x00e1, 0x00e9, 0x00ed, 0x00f3, 0x00fa, 0x00bf, 0x00fc, 0x00f1, 0x00e8, 0x00e0 }
|
||||
},
|
||||
{ // 6
|
||||
"Italian",
|
||||
{ 0x00a3, 0x0024, 0x00e9, 0x00b0, 0x00e7, 0x00bb, 0x005e, 0x0023, 0x00f9, 0x00e0, 0x00f2, 0x00e8, 0x00ec }
|
||||
},
|
||||
{ // 7
|
||||
"Rumanian",
|
||||
{ 0x0023, 0x00a4, 0x0162, 0x00c2, 0x015e, 0x0102, 0x00ce, 0x0131, 0x0163, 0x00e2, 0x015f, 0x0103, 0x00ee }
|
||||
},
|
||||
{ // 8
|
||||
"Polish",
|
||||
{ 0x0023, 0x0144, 0x0105, 0x017b, 0x015a, 0x0141, 0x0107, 0x00f3, 0x0119, 0x017c, 0x015b, 0x0142, 0x017a }
|
||||
},
|
||||
{ // 9
|
||||
"Turkish",
|
||||
{ 0x0054, 0x011f, 0x0130, 0x015e, 0x00d6, 0x00c7, 0x00dc, 0x011e, 0x0131, 0x015f, 0x00f6, 0x00e7, 0x00fc }
|
||||
},
|
||||
{ // a
|
||||
"Serbian, Croatian, Slovenian",
|
||||
{ 0x0023, 0x00cb, 0x010c, 0x0106, 0x017d, 0x0110, 0x0160, 0x00eb, 0x010d, 0x0107, 0x017e, 0x0111, 0x0161 }
|
||||
},
|
||||
{ // b
|
||||
"Estonian",
|
||||
{ 0x0023, 0x00f5, 0x0160, 0x00c4, 0x00d6, 0x017e, 0x00dc, 0x00d5, 0x0161, 0x00e4, 0x00f6, 0x017e, 0x00fc }
|
||||
},
|
||||
{ // c
|
||||
"Lettish, Lithuanian",
|
||||
{ 0x0023, 0x0024, 0x0160, 0x0117, 0x0119, 0x017d, 0x010d, 0x016b, 0x0161, 0x0105, 0x0173, 0x017e, 0x012f }
|
||||
}
|
||||
};
|
||||
|
||||
// References to the G0_LATIN_NATIONAL_SUBSETS array
|
||||
const uint8_t G0_LATIN_NATIONAL_SUBSETS_MAP[56] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x01, 0x02, 0x03, 0x04, 0xff, 0x06, 0xff,
|
||||
0x00, 0x01, 0x02, 0x09, 0x04, 0x05, 0x06, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0x07,
|
||||
0xff, 0xff, 0x0b, 0x03, 0x04, 0xff, 0x0c, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x09, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
// --- G2 ----------------------------------------------------------------------
|
||||
|
||||
const uint16_t G2[1][96] = {
|
||||
{ // Latin G2 Supplementary Set
|
||||
0x0020, 0x00a1, 0x00a2, 0x00a3, 0x0024, 0x00a5, 0x0023, 0x00a7, 0x00a4, 0x2018, 0x201c, 0x00ab, 0x2190, 0x2191, 0x2192, 0x2193,
|
||||
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00d7, 0x00b5, 0x00b6, 0x00b7, 0x00f7, 0x2019, 0x201d, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
|
||||
0x0020, 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, 0x0000, 0x030a, 0x0327, 0x005f, 0x030b, 0x0328, 0x030c,
|
||||
0x2015, 0x00b9, 0x00ae, 0x00a9, 0x2122, 0x266a, 0x20ac, 0x2030, 0x03B1, 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e,
|
||||
0x03a9, 0x00c6, 0x0110, 0x00aa, 0x0126, 0x0000, 0x0132, 0x013f, 0x0141, 0x00d8, 0x0152, 0x00ba, 0x00de, 0x0166, 0x014a, 0x0149,
|
||||
0x0138, 0x00e6, 0x0111, 0x00f0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00f8, 0x0153, 0x00df, 0x00fe, 0x0167, 0x014b, 0x0020
|
||||
}
|
||||
// { // Cyrillic G2 Supplementary Set
|
||||
// },
|
||||
// { // Greek G2 Supplementary Set
|
||||
// },
|
||||
// { // Arabic G2 Supplementary Set
|
||||
// }
|
||||
};
|
||||
|
||||
const uint16_t G2_ACCENTS[15][52] = {
|
||||
// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
{ // grave
|
||||
0x00c0, 0x0000, 0x0000, 0x0000, 0x00c8, 0x0000, 0x0000, 0x0000, 0x00cc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d2, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x00d9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e0, 0x0000, 0x0000, 0x0000, 0x00e8, 0x0000,
|
||||
0x0000, 0x0000, 0x00ec, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f9, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // acute
|
||||
0x00c1, 0x0000, 0x0106, 0x0000, 0x00c9, 0x0000, 0x0000, 0x0000, 0x00cd, 0x0000, 0x0000, 0x0139, 0x0000, 0x0143, 0x00d3, 0x0000,
|
||||
0x0000, 0x0154, 0x015a, 0x0000, 0x00da, 0x0000, 0x0000, 0x0000, 0x00dd, 0x0179, 0x00e1, 0x0000, 0x0107, 0x0000, 0x00e9, 0x0000,
|
||||
0x0123, 0x0000, 0x00ed, 0x0000, 0x0000, 0x013a, 0x0000, 0x0144, 0x00f3, 0x0000, 0x0000, 0x0155, 0x015b, 0x0000, 0x00fa, 0x0000,
|
||||
0x0000, 0x0000, 0x00fd, 0x017a
|
||||
},
|
||||
{ // circumflex
|
||||
0x00c2, 0x0000, 0x0108, 0x0000, 0x00ca, 0x0000, 0x011c, 0x0124, 0x00ce, 0x0134, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d4, 0x0000,
|
||||
0x0000, 0x0000, 0x015c, 0x0000, 0x00db, 0x0000, 0x0174, 0x0000, 0x0176, 0x0000, 0x00e2, 0x0000, 0x0109, 0x0000, 0x00ea, 0x0000,
|
||||
0x011d, 0x0125, 0x00ee, 0x0135, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f4, 0x0000, 0x0000, 0x0000, 0x015d, 0x0000, 0x00fb, 0x0000,
|
||||
0x0175, 0x0000, 0x0177, 0x0000
|
||||
},
|
||||
{ // tilde
|
||||
0x00c3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0128, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d1, 0x00d5, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0168, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0129, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f1, 0x00f5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0169, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // macron
|
||||
0x0100, 0x0000, 0x0000, 0x0000, 0x0112, 0x0000, 0x0000, 0x0000, 0x012a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014c, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x016a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0101, 0x0000, 0x0000, 0x0000, 0x0113, 0x0000,
|
||||
0x0000, 0x0000, 0x012b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016b, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // breve
|
||||
0x0102, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x011e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0103, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x011f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // dot
|
||||
0x0000, 0x0000, 0x010a, 0x0000, 0x0116, 0x0000, 0x0120, 0x0000, 0x0130, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017b, 0x0000, 0x0000, 0x010b, 0x0000, 0x0117, 0x0000,
|
||||
0x0121, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x017c
|
||||
},
|
||||
{ // umlaut
|
||||
0x00c4, 0x0000, 0x0000, 0x0000, 0x00cb, 0x0000, 0x0000, 0x0000, 0x00cf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d6, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x00dc, 0x0000, 0x0000, 0x0000, 0x0178, 0x0000, 0x00e4, 0x0000, 0x0000, 0x0000, 0x00eb, 0x0000,
|
||||
0x0000, 0x0000, 0x00ef, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00fc, 0x0000,
|
||||
0x0000, 0x0000, 0x00ff, 0x0000
|
||||
},
|
||||
{ 0 },
|
||||
{ // ring
|
||||
0x00c5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x016e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016f, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // cedilla
|
||||
0x0000, 0x0000, 0x00c7, 0x0000, 0x0000, 0x0000, 0x0122, 0x0000, 0x0000, 0x0000, 0x0136, 0x013b, 0x0000, 0x0145, 0x0000, 0x0000,
|
||||
0x0000, 0x0156, 0x015e, 0x0162, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00e7, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0137, 0x013c, 0x0000, 0x0146, 0x0000, 0x0000, 0x0000, 0x0157, 0x015f, 0x0163, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ 0 },
|
||||
{ // double acute
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0150, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0170, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0171, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // ogonek
|
||||
0x0104, 0x0000, 0x0000, 0x0000, 0x0118, 0x0000, 0x0000, 0x0000, 0x012e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0105, 0x0000, 0x0000, 0x0000, 0x0119, 0x0000,
|
||||
0x0000, 0x0000, 0x012f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0173, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
},
|
||||
{ // caron
|
||||
0x0000, 0x0000, 0x010c, 0x010e, 0x011a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x013d, 0x0000, 0x0147, 0x0000, 0x0000,
|
||||
0x0000, 0x0158, 0x0160, 0x0164, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017d, 0x0000, 0x0000, 0x010d, 0x010f, 0x011b, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x013e, 0x0000, 0x0148, 0x0000, 0x0000, 0x0000, 0x0159, 0x0161, 0x0165, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x017e
|
||||
}
|
||||
};
|
||||
|
||||
int tlt_print_seen_pages(struct lib_cc_decode *dec_ctx);
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
76
src/lib_ccx/ts_functions.h
Normal file
76
src/lib_ccx/ts_functions.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#ifndef TS_FUNCTION_H
|
||||
#define TS_FUNCTION_H
|
||||
|
||||
struct ts_payload
|
||||
{
|
||||
unsigned char *start; // Payload start
|
||||
unsigned length; // Payload length
|
||||
unsigned pesstart; // PES or PSI start
|
||||
unsigned pid; // Stream PID
|
||||
int counter; // continuity counter
|
||||
int transport_error; // 0 = packet OK, non-zero damaged
|
||||
int64_t pcr;
|
||||
unsigned char section_buf[4098];
|
||||
int section_index;
|
||||
int section_size;
|
||||
};
|
||||
|
||||
struct PAT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned char *last_pmt_payload;
|
||||
unsigned last_pmt_length;
|
||||
};
|
||||
|
||||
struct PMT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned elementary_PID;
|
||||
enum ccx_stream_type stream_type;
|
||||
unsigned printable_stream_type;
|
||||
};
|
||||
|
||||
struct PSI_buffer
|
||||
{
|
||||
uint32_t prev_ccounter;
|
||||
uint8_t *buffer;
|
||||
uint32_t buffer_length;
|
||||
uint32_t ccounter;
|
||||
};
|
||||
|
||||
struct EPG_rating
|
||||
{
|
||||
char country_code[4];
|
||||
uint8_t age;
|
||||
};
|
||||
|
||||
struct EPG_event
|
||||
{
|
||||
uint32_t id;
|
||||
char start_time_string[21]; //"YYYYMMDDHHMMSS +0000" = 20 chars
|
||||
char end_time_string[21];
|
||||
uint8_t running_status;
|
||||
uint8_t free_ca_mode;
|
||||
char ISO_639_language_code[4];
|
||||
char *event_name;
|
||||
char *text;
|
||||
char extended_ISO_639_language_code[4];
|
||||
char *extended_text;
|
||||
uint8_t has_simple;
|
||||
struct EPG_rating *ratings;
|
||||
uint32_t num_ratings;
|
||||
uint8_t *categories;
|
||||
uint32_t num_categories;
|
||||
uint16_t service_id;
|
||||
long long int count; //incremented by one each time the event is updated
|
||||
uint8_t live_output; //boolean flag, true if this event has been output
|
||||
};
|
||||
|
||||
#define EPG_MAX_EVENTS 60*24*7
|
||||
struct EIT_program
|
||||
{
|
||||
uint32_t array_len;
|
||||
struct EPG_event epg_events[EPG_MAX_EVENTS];
|
||||
};
|
||||
#endif
|
||||
278
src/lib_ccx/ts_info.c
Normal file
278
src/lib_ccx/ts_info.c
Normal file
@@ -0,0 +1,278 @@
|
||||
#include "ccx_demuxer.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
|
||||
/**
|
||||
We need stream info from PMT table when any of the following Condition meets:
|
||||
1) Dont have any caption stream registered to be extracted
|
||||
2) Want a streams per program, and program_number has never been registered
|
||||
3) We need single stream and its info about codec and buffertype is incomplete
|
||||
*/
|
||||
int need_capInfo(struct ccx_demuxer *ctx, int program_number)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
if(list_empty(&ctx->cinfo_tree.all_stream))
|
||||
{
|
||||
return CCX_TRUE;
|
||||
}
|
||||
|
||||
if(ctx->ts_allprogram == CCX_TRUE)
|
||||
{
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.pg_stream, pg_stream, struct cap_info)
|
||||
{
|
||||
if (iter->program_number == program_number)
|
||||
return CCX_FALSE;
|
||||
}
|
||||
return CCX_TRUE;
|
||||
}
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->codec == CCX_CODEC_NONE)
|
||||
return CCX_TRUE;
|
||||
if (iter->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM)
|
||||
return CCX_TRUE;
|
||||
}
|
||||
|
||||
return CCX_FALSE;
|
||||
}
|
||||
|
||||
void ignore_other_stream(struct ccx_demuxer *ctx, int pid)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->pid != pid)
|
||||
iter->ignore = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int get_programme_number(struct ccx_demuxer *ctx, int pid)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->pid == pid)
|
||||
return iter->program_number;
|
||||
}
|
||||
return CCX_UNKNOWN;
|
||||
}
|
||||
|
||||
struct cap_info *get_sib_stream_by_type(struct cap_info* program, enum ccx_code_type type)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
list_for_each_entry(iter, &program->sib_head, sib_stream, struct cap_info)
|
||||
{
|
||||
if(iter->codec == type)
|
||||
return iter;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
struct cap_info* get_best_sib_stream(struct cap_info* program)
|
||||
{
|
||||
struct cap_info* info;
|
||||
|
||||
info = get_sib_stream_by_type(program, CCX_CODEC_TELETEXT);
|
||||
if(info)
|
||||
return info;
|
||||
|
||||
info = get_sib_stream_by_type(program, CCX_CODEC_DVB);
|
||||
if(info)
|
||||
return info;
|
||||
|
||||
info = get_sib_stream_by_type(program, CCX_CODEC_ATSC_CC);
|
||||
if(info)
|
||||
return info;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ignore_other_sib_stream(struct cap_info* head, int pid)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
list_for_each_entry(iter, &head->sib_head, sib_stream, struct cap_info)
|
||||
{
|
||||
if(iter->pid != pid)
|
||||
iter->ignore = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int get_best_stream(struct ccx_demuxer *ctx)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->codec == CCX_CODEC_TELETEXT)
|
||||
return iter->pid;
|
||||
}
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->codec == CCX_CODEC_DVB)
|
||||
return iter->pid;
|
||||
}
|
||||
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->codec == CCX_CODEC_ISDB_CC)
|
||||
return iter->pid;
|
||||
}
|
||||
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->codec == CCX_CODEC_ATSC_CC)
|
||||
return iter->pid;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct demuxer_data *get_data_stream(struct demuxer_data *data, int pid)
|
||||
{
|
||||
struct demuxer_data *ptr = data;
|
||||
for(ptr = data; ptr; ptr = ptr->next_stream)
|
||||
if(ptr->stream_pid == pid && ptr->len > 0)
|
||||
return ptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
int need_capInfo_for_pid(struct ccx_demuxer *ctx, int pid)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
if(list_empty(&ctx->cinfo_tree.all_stream))
|
||||
{
|
||||
return CCX_FALSE;
|
||||
}
|
||||
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if (iter->pid == pid && iter->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM)
|
||||
return CCX_TRUE;
|
||||
}
|
||||
return CCX_FALSE;
|
||||
}
|
||||
|
||||
static void* init_private_data(enum ccx_code_type codec)
|
||||
{
|
||||
switch(codec)
|
||||
{
|
||||
case CCX_CODEC_TELETEXT:
|
||||
return telxcc_init();
|
||||
case CCX_CODEC_DVB:
|
||||
return dvbsub_init_decoder(NULL);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
int update_capinfo(struct ccx_demuxer *ctx, int pid, enum ccx_stream_type stream, enum ccx_code_type codec, int pn, void *private_data)
|
||||
{
|
||||
struct cap_info* ptr;
|
||||
struct cap_info* tmp;
|
||||
struct cap_info* program_iter;
|
||||
if(!ctx)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->ts_datastreamtype != CCX_STREAM_TYPE_UNKNOWNSTREAM && ctx->ts_datastreamtype != stream)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = &ctx->cinfo_tree;
|
||||
|
||||
list_for_each_entry(tmp, &ptr->all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if (tmp->pid == pid)
|
||||
{
|
||||
if(tmp->stream == CCX_STREAM_TYPE_UNKNOWNSTREAM || tmp->codec == CCX_CODEC_NONE)
|
||||
{
|
||||
if(stream != CCX_STREAM_TYPE_UNKNOWNSTREAM)
|
||||
tmp->stream = stream;
|
||||
if(codec != CCX_CODEC_NONE)
|
||||
{
|
||||
tmp->codec = codec;
|
||||
tmp->codec_private_data = init_private_data(codec);
|
||||
}
|
||||
|
||||
tmp->saw_pesstart = 0;
|
||||
tmp->capbuflen = 0;
|
||||
tmp->capbufsize = 0;
|
||||
tmp->ignore = 0;
|
||||
if(private_data)
|
||||
tmp->codec_private_data = private_data;
|
||||
}
|
||||
return CCX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if( ctx->flag_ts_forced_cappid == CCX_TRUE)
|
||||
return CCX_EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(struct cap_info));
|
||||
if(!tmp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp->pid = pid;
|
||||
tmp->stream = stream;
|
||||
tmp->codec = codec;
|
||||
tmp->program_number = pn;
|
||||
|
||||
tmp->saw_pesstart = 0;
|
||||
tmp->capbuflen = 0;
|
||||
tmp->capbufsize = 0;
|
||||
tmp->capbuf = NULL;
|
||||
tmp->ignore = CCX_FALSE;
|
||||
if(!private_data && codec != CCX_CODEC_NONE)
|
||||
tmp->codec_private_data = init_private_data(codec);
|
||||
else
|
||||
tmp->codec_private_data = private_data;
|
||||
|
||||
list_add_tail( &(tmp->all_stream), &(ptr->all_stream) );
|
||||
|
||||
list_for_each_entry(program_iter, &ptr->pg_stream, pg_stream, struct cap_info)
|
||||
{
|
||||
if (program_iter->program_number == pn)
|
||||
{
|
||||
list_add_tail( &(tmp->sib_stream), &(program_iter->sib_head) );
|
||||
return CCX_OK;
|
||||
}
|
||||
}
|
||||
INIT_LIST_HEAD(&(tmp->sib_head));
|
||||
list_add_tail( &(tmp->sib_stream), &(tmp->sib_head) );
|
||||
list_add_tail( &(tmp->pg_stream), &(ptr->pg_stream) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dinit_cap (struct ccx_demuxer *ctx)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
while(!list_empty(&ctx->cinfo_tree.all_stream))
|
||||
{
|
||||
iter = list_entry(ctx->cinfo_tree.all_stream.next, struct cap_info, all_stream);
|
||||
list_del(&iter->all_stream);
|
||||
free(iter);
|
||||
}
|
||||
INIT_LIST_HEAD(&ctx->cinfo_tree.all_stream);
|
||||
INIT_LIST_HEAD(&ctx->cinfo_tree.sib_stream);
|
||||
INIT_LIST_HEAD(&ctx->cinfo_tree.pg_stream);
|
||||
}
|
||||
|
||||
|
||||
struct cap_info * get_cinfo(struct ccx_demuxer *ctx, int pid)
|
||||
{
|
||||
struct cap_info* iter;
|
||||
|
||||
list_for_each_entry(iter, &ctx->cinfo_tree.all_stream, all_stream, struct cap_info)
|
||||
{
|
||||
if(iter->pid == pid && iter->codec != CCX_CODEC_NONE && iter->stream != CCX_STREAM_TYPE_UNKNOWNSTREAM)
|
||||
return iter;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
#include "utility.h"
|
||||
#include <stdbool.h>
|
||||
#ifdef WIN32
|
||||
#include "..\\win_iconv\\win_iconv.h"
|
||||
#include "..\\win_iconv\\iconv.h"
|
||||
#else
|
||||
#include "iconv.h"
|
||||
#endif
|
||||
@@ -81,7 +81,7 @@ void EPG_DVB_calc_start_time(struct EPG_event *event, uint64_t time)
|
||||
y = y + k + 1900;
|
||||
m = m - 1 - k*12;
|
||||
|
||||
sprintf(event->start_time_string, "%02d%02d%02d%06x +0000",y,m,d,time&0xffffff);
|
||||
sprintf(event->start_time_string, "%02ld%02ld%02ld%06llx +0000",y,m,d,time&0xffffff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +193,50 @@ void EPG_print_event(struct EPG_event *event, uint32_t channel, FILE *f)
|
||||
fprintf(f, " </program>\n");
|
||||
}
|
||||
|
||||
void EPG_output_net(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
unsigned j;
|
||||
struct EPG_event *event;
|
||||
|
||||
/* TODO: don't remove untill someone fixes segfault with -xmltv 2 */
|
||||
if (ctx->demux_ctx == NULL)
|
||||
return;
|
||||
|
||||
if (ctx->demux_ctx->nb_program == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
if (ctx->demux_ctx->pinfo[i].program_number == ccx_options.demux_cfg.ts_forced_program)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ctx->demux_ctx->nb_program)
|
||||
return;
|
||||
|
||||
for (j = 0; j < ctx->eit_programs[i].array_len; j++)
|
||||
{
|
||||
event = &(ctx->eit_programs[i].epg_events[j]);
|
||||
if (event->live_output == true)
|
||||
continue;
|
||||
|
||||
event->live_output = true;
|
||||
|
||||
char *category = NULL;
|
||||
if (event->num_categories > 0)
|
||||
category = EPG_DVB_content_type_to_string(event->categories[0]);
|
||||
|
||||
net_send_epg(
|
||||
event->start_time_string, event->end_time_string,
|
||||
event->event_name,
|
||||
event->extended_text,
|
||||
event->ISO_639_language_code,
|
||||
category
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Creates fills and closes a new XMLTV file for live mode output.
|
||||
// File should include only events not previously output.
|
||||
void EPG_output_live(struct lib_ccx_ctx *ctx)
|
||||
@@ -200,7 +244,7 @@ void EPG_output_live(struct lib_ccx_ctx *ctx)
|
||||
int c=false, i, j;
|
||||
FILE *f;
|
||||
char *filename, *finalfilename;
|
||||
for(i=0; i<pmt_array_length; i++)
|
||||
for(i=0; i < ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
if(ctx->eit_programs[i].epg_events[j].live_output==false)
|
||||
@@ -216,24 +260,24 @@ void EPG_output_live(struct lib_ccx_ctx *ctx)
|
||||
f = fopen(filename, "w");
|
||||
|
||||
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
|
||||
for(i=0; i<pmt_array_length; i++)
|
||||
for(i=0; i < ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <channel id=\"%i\">\n", ctx->demux_ctx->pinfo[i].program_number);
|
||||
fprintf(f, " <display-name>%i</display-name>\n", ctx->demux_ctx->pinfo[i].program_number);
|
||||
fprintf(f, " </channel>\n");
|
||||
}
|
||||
for(i=0; i<pmt_array_length; i++)
|
||||
for(i=0; i < ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
if(ctx->eit_programs[i].epg_events[j].live_output==false)
|
||||
{
|
||||
ctx->eit_programs[i].epg_events[j].live_output=true;
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
|
||||
}
|
||||
}
|
||||
fprintf(f, "</tv>");
|
||||
fclose(f);
|
||||
finalfilename = malloc(strlen(ctx->wbout1.filename)+30);
|
||||
finalfilename = malloc(strlen(filename)+30);
|
||||
memcpy(finalfilename, filename, strlen(filename)-5);
|
||||
finalfilename[strlen(filename)-5]='\0';
|
||||
rename(filename, finalfilename);
|
||||
@@ -248,39 +292,49 @@ void EPG_output(struct lib_ccx_ctx *ctx)
|
||||
FILE *f;
|
||||
char *filename;
|
||||
int i,j, ce;
|
||||
|
||||
filename = malloc(strlen(ctx->basefilename) + 9);
|
||||
if(filename == NULL)
|
||||
return;
|
||||
|
||||
memcpy(filename, ctx->basefilename, strlen(ctx->basefilename)+1);
|
||||
strcat(filename, "_epg.xml");
|
||||
f = fopen(filename, "w");
|
||||
free(filename);
|
||||
freep(&filename);
|
||||
|
||||
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
|
||||
for(i=0; i<pmt_array_length; i++)
|
||||
for(i=0; i<ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <channel id=\"%i\">\n", ctx->demux_ctx->pinfo[i].program_number);
|
||||
fprintf(f, " <display-name>");
|
||||
if(ctx->demux_ctx->pinfo[i].name[0] != '\0')
|
||||
EPG_fprintxml(f, ctx->demux_ctx->pinfo[i].name);
|
||||
else
|
||||
fprintf(f, "%i\n", ctx->demux_ctx->pinfo[i].program_number);
|
||||
fprintf(f, "</display-name>\n");
|
||||
fprintf(f, " </channel>\n");
|
||||
}
|
||||
if(ccx_options.xmltvonlycurrent==0)
|
||||
{ // print all events
|
||||
for(i=0; i<pmt_array_length; i++)
|
||||
for(i=0; i<ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
|
||||
}
|
||||
|
||||
if(pmt_array_length==0) //Stream has no PMT, fall back to unordered events
|
||||
if(ctx->demux_ctx->nb_program==0) //Stream has no PMT, fall back to unordered events
|
||||
for(j=0; j<ctx->eit_programs[TS_PMT_MAP_SIZE].array_len; j++)
|
||||
EPG_print_event(&ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j], ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j].service_id, f);
|
||||
}
|
||||
else
|
||||
{ // print current events only
|
||||
for(i=0; i<pmt_array_length; i++)
|
||||
for(i=0; i<ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
ce = ctx->eit_current_events[i];
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
{
|
||||
if(ce==ctx->eit_programs[i].epg_events[j].id)
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,9 +775,9 @@ void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32
|
||||
event.num_ratings=0;
|
||||
event.num_categories=0;
|
||||
event.live_output=false;
|
||||
for (i = 0; i < pmt_array_length; i++)
|
||||
for (i = 0; i < ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
if (pmt_array[i].program_number == ctx->ATSC_source_pg_map[source_id])
|
||||
if (ctx->demux_ctx->pinfo[i].program_number == ctx->ATSC_source_pg_map[source_id])
|
||||
pmt_map=i;
|
||||
}
|
||||
|
||||
@@ -816,14 +870,14 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
|
||||
uint16_t service_id;
|
||||
int32_t pmt_map = -1;
|
||||
int i;
|
||||
int hasnew=false;
|
||||
int hasnew = false;
|
||||
struct EPG_event event;
|
||||
uint8_t section_number;
|
||||
uint8_t last_section_number;
|
||||
uint8_t segment_last_section_number;
|
||||
uint32_t events_length = section_length - 11;
|
||||
uint8_t *offset=payload_start;
|
||||
uint32_t remaining=events_length;
|
||||
uint32_t events_length;
|
||||
uint8_t *offset;
|
||||
uint32_t remaining;
|
||||
|
||||
|
||||
if(size < 13)
|
||||
@@ -840,17 +894,17 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
|
||||
offset = payload_start;
|
||||
remaining = events_length;
|
||||
|
||||
for (i = 0; i < pmt_array_length; i++)
|
||||
for (i = 0; i < ctx->demux_ctx->nb_program; i++)
|
||||
{
|
||||
if (pmt_array[i].program_number == service_id)
|
||||
pmt_map=i;
|
||||
if (ctx->demux_ctx->pinfo[i].program_number == service_id)
|
||||
pmt_map = i;
|
||||
}
|
||||
|
||||
//For any service we don't have an PMT for (yet), store it in the special last array pos.
|
||||
if(pmt_map==-1)
|
||||
pmt_map=TS_PMT_MAP_SIZE;
|
||||
if(pmt_map == -1)
|
||||
pmt_map = TS_PMT_MAP_SIZE;
|
||||
|
||||
if(events_length>size-14)
|
||||
if(events_length > size-14)
|
||||
{
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT packet size detected.\n");
|
||||
//XXX hack to override segfault, we should concat packets instead
|
||||
@@ -923,7 +977,7 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
|
||||
//handle outputing to xml files
|
||||
void EPG_handle_output(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int cur_sec = (int) ((ctx->global_timestamp-ctx->min_global_timestamp) / 1000);
|
||||
int cur_sec = (int) ((ctx->demux_ctx->global_timestamp - ctx->demux_ctx->min_global_timestamp) / 1000);
|
||||
if(ccx_options.xmltv==1 || ccx_options.xmltv==3)
|
||||
{ //full outout
|
||||
if(ccx_options.xmltvoutputinterval!=0 && cur_sec>ctx->epg_last_output+ccx_options.xmltvliveinterval)
|
||||
@@ -932,12 +986,15 @@ void EPG_handle_output(struct lib_ccx_ctx *ctx)
|
||||
EPG_output(ctx);
|
||||
}
|
||||
}
|
||||
if(ccx_options.xmltv==2 || ccx_options.xmltv==3)
|
||||
if(ccx_options.xmltv==2 || ccx_options.xmltv==3 || ccx_options.send_to_srv)
|
||||
{ //live output
|
||||
if(cur_sec>ctx->epg_last_live_output+ccx_options.xmltvliveinterval)
|
||||
{
|
||||
ctx->epg_last_live_output=cur_sec;
|
||||
EPG_output_live(ctx);
|
||||
if (ccx_options.send_to_srv)
|
||||
EPG_output_net(ctx);
|
||||
else
|
||||
EPG_output_live(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1036,9 +1093,12 @@ void parse_EPG_packet(struct lib_ccx_ctx *ctx)
|
||||
void EPG_free(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int i = 0, j;
|
||||
if(ccx_options.xmltv==2 || ccx_options.xmltv==3)
|
||||
if(ccx_options.xmltv==2 || ccx_options.xmltv==3 || ccx_options.send_to_srv)
|
||||
{
|
||||
EPG_output_live(ctx);
|
||||
if (ccx_options.send_to_srv)
|
||||
EPG_output_net(ctx);
|
||||
else
|
||||
EPG_output_live(ctx);
|
||||
}
|
||||
for (i = 0; i < TS_PMT_MAP_SIZE; i++)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,131 @@
|
||||
#include <signal.h>
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "activity.h"
|
||||
|
||||
int temp_debug = 0; // This is a convenience variable used to enable/disable debug on variable conditions. Find references to understand.
|
||||
|
||||
|
||||
|
||||
static uint32_t crc32_table [] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
|
||||
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
|
||||
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
|
||||
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
|
||||
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
|
||||
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
|
||||
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
|
||||
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
|
||||
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
|
||||
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
|
||||
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
|
||||
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
|
||||
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
|
||||
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
|
||||
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
|
||||
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
|
||||
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
|
||||
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
|
||||
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
|
||||
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
|
||||
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
int verify_crc32(uint8_t *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int32_t crc = -1;
|
||||
for (i = 0; i < len; i++)
|
||||
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (buf[i] & 0xff)) & 0xff];
|
||||
return crc?CCX_FALSE:CCX_TRUE;
|
||||
}
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt)
|
||||
{
|
||||
unsigned ss=0, mm=0, hh=0;
|
||||
int value=-1;
|
||||
int colons=0;
|
||||
const char *c=s;
|
||||
while (*c)
|
||||
{
|
||||
if (*c==':')
|
||||
{
|
||||
if (value==-1) // : at the start, or ::, etc
|
||||
return -1;
|
||||
colons++;
|
||||
if (colons>2) // Max 2, for HH:MM:SS
|
||||
return -1;
|
||||
hh=mm;
|
||||
mm=ss;
|
||||
ss=value;
|
||||
value=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isdigit (*c)) // Only : or digits, so error
|
||||
return -1;
|
||||
if (value==-1)
|
||||
value=*c-'0';
|
||||
else
|
||||
value=value*10+*c-'0';
|
||||
}
|
||||
c++;
|
||||
}
|
||||
hh = mm;
|
||||
mm = ss;
|
||||
ss = value;
|
||||
if (mm > 59 || ss > 59)
|
||||
return -1;
|
||||
bt->set = 1;
|
||||
bt->hh = hh;
|
||||
bt->mm = mm;
|
||||
bt->ss = ss;
|
||||
LLONG secs = (hh * 3600 + mm * 60 + ss);
|
||||
bt->time_in_ms = secs*1000;
|
||||
return 0;
|
||||
}
|
||||
void timestamp_to_srttime(uint64_t timestamp, char *buffer)
|
||||
{
|
||||
uint64_t p = timestamp;
|
||||
@@ -250,3 +372,142 @@ void m_signal(int sig, void (*func)(int))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
char *get_basename(char *filename)
|
||||
{
|
||||
char *c;
|
||||
int len;
|
||||
char *basefilename;
|
||||
|
||||
if(!filename)
|
||||
return NULL;
|
||||
|
||||
len = strlen(filename);
|
||||
basefilename = (char *) malloc(len+1);
|
||||
if (basefilename == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy (basefilename, filename);
|
||||
|
||||
for (c = basefilename + len; c > basefilename && *c != '.'; c--)
|
||||
{;} // Get last .
|
||||
if (*c == '.')
|
||||
*c = 0;
|
||||
|
||||
return basefilename;
|
||||
}
|
||||
|
||||
char *get_file_extension(enum ccx_output_format write_format)
|
||||
{
|
||||
switch (write_format)
|
||||
{
|
||||
case CCX_OF_RAW:
|
||||
return strdup(".raw");
|
||||
case CCX_OF_SRT:
|
||||
return strdup(".srt");
|
||||
case CCX_OF_WEBVTT:
|
||||
return strdup (".vtt");
|
||||
case CCX_OF_SAMI:
|
||||
return strdup(".smi");
|
||||
case CCX_OF_SMPTETT:
|
||||
return strdup(".ttml");
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
return strdup(".txt");
|
||||
case CCX_OF_RCWT:
|
||||
return strdup(".bin");
|
||||
case CCX_OF_SPUPNG:
|
||||
return strdup(".xml");
|
||||
case CCX_OF_DVDRAW:
|
||||
return strdup(".dvdraw");
|
||||
case CCX_OF_SIMPLE_XML:
|
||||
return strdup(".xml");
|
||||
case CCX_OF_NULL:
|
||||
return NULL;
|
||||
default:
|
||||
mprint ("write_format doesn't have any legal value, this is a bug.\n");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *create_outfilename(const char *basename, const char *suffix, const char *extension)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
size_t blen, slen, elen;
|
||||
|
||||
if(basename)
|
||||
blen = strlen(basename);
|
||||
else
|
||||
blen = 0;
|
||||
|
||||
if(suffix)
|
||||
slen = strlen(suffix);
|
||||
else
|
||||
slen = 0;
|
||||
|
||||
if(extension)
|
||||
elen = strlen(extension);
|
||||
else
|
||||
elen = 0;
|
||||
if ( (elen + slen + blen) <= 0)
|
||||
return NULL;
|
||||
|
||||
ptr = malloc(elen + slen + blen + 1);
|
||||
if(!ptr)
|
||||
return NULL;
|
||||
|
||||
ptr[0] = '\0';
|
||||
|
||||
if(basename)
|
||||
strcat(ptr, basename);
|
||||
if(suffix)
|
||||
strcat(ptr, suffix);
|
||||
if(extension)
|
||||
strcat(ptr, extension);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t utf16_to_utf8(unsigned short utf16_char, unsigned char *out)
|
||||
{
|
||||
if (utf16_char < 0x80) {
|
||||
out[0] = (unsigned char)((utf16_char >> 0 & 0x7F) | 0x00);
|
||||
return 1;
|
||||
} else if (utf16_char < 0x0800) {
|
||||
out[0] = (unsigned char)((utf16_char >> 6 & 0x1F) | 0xC0);
|
||||
out[1] = (unsigned char)((utf16_char >> 0 & 0x3F) | 0x80);
|
||||
return 2;
|
||||
} else if (utf16_char < 0x010000) {
|
||||
out[0] = (unsigned char)((utf16_char >> 12 & 0x0F) | 0xE0);
|
||||
out[1] = (unsigned char)((utf16_char >> 6 & 0x3F) | 0x80);
|
||||
out[2] = (unsigned char)((utf16_char >> 0 & 0x3F) | 0x80);
|
||||
return 3;
|
||||
} else if (utf16_char < 0x110000) {
|
||||
out[0] = (unsigned char)((utf16_char >> 18 & 0x07) | 0xF0);
|
||||
out[1] = (unsigned char)((utf16_char >> 12 & 0x3F) | 0x80);
|
||||
out[2] = (unsigned char)((utf16_char >> 6 & 0x3F) | 0x80);
|
||||
out[3] = (unsigned char)((utf16_char >> 0 & 0x3F) | 0x80);
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
char *strndup(const char *s, size_t n)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = (char *)malloc(n + 1);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
memcpy(p, s, n);
|
||||
p[n] = '\0';
|
||||
return p;
|
||||
}
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr)
|
||||
{
|
||||
strtok_s(str, delim, saveptr);
|
||||
}
|
||||
#endif //_WIN32
|
||||
|
||||
@@ -10,7 +10,23 @@
|
||||
#define RL16(x) (*(unsigned short int*)(x))
|
||||
#define RB16(x) (ntohs(*(unsigned short int*)(x)))
|
||||
|
||||
#define RB24(x) ( ((unsigned char*)(x))[0] << 16 | ((unsigned char*)(x))[1] << 8 | ((unsigned char*)(x))[2] )
|
||||
|
||||
#define CCX_NOPTS ((int64_t)UINT64_C(0x8000000000000000))
|
||||
|
||||
extern int temp_debug;
|
||||
void init_boundary_time (struct ccx_boundary_time *bt);
|
||||
void print_error (int mode, const char *fmt, ...);
|
||||
#endif
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt);
|
||||
char *get_basename(char *filename);
|
||||
char *get_file_extension(enum ccx_output_format write_format);
|
||||
char *create_outfilename(const char *basename, const char *suffix, const char *extension);
|
||||
int verify_crc32(uint8_t *buf, int len);
|
||||
size_t utf16_to_utf8(unsigned short utf16_char, unsigned char *out);
|
||||
|
||||
#ifdef _WIN32
|
||||
char *strndup(const char *s, size_t n);
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||
#endif //_WIN32
|
||||
|
||||
#endif //CC_UTILITY_H
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "wtv_constants.h"
|
||||
#include "activity.h"
|
||||
#include "file_buffer.h"
|
||||
|
||||
int check_stream_id(int stream_id, int video_streams[], int num_streams);
|
||||
int add_skip_chunks(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag);
|
||||
int add_skip_chunks(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag);
|
||||
void init_chunked_buffer(struct wtv_chunked_buffer *cb);
|
||||
uint64_t get_meta_chunk_start(uint64_t offset);
|
||||
uint64_t time_to_pes_time(uint64_t time);
|
||||
void add_chunk(struct wtv_chunked_buffer *cb, uint64_t value);
|
||||
int qsort_cmpint (const void * a, const void * b);
|
||||
void get_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
|
||||
void skip_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
|
||||
int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb);
|
||||
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb);
|
||||
void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
|
||||
void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size);
|
||||
int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb);
|
||||
|
||||
// Helper function for qsort (64bit int sort)
|
||||
int qsort_cmpint (const void * a, const void * b)
|
||||
@@ -58,29 +59,29 @@ uint64_t time_to_pes_time(uint64_t time)
|
||||
|
||||
// Read the actual values of the passed lookup offset and add them to
|
||||
// the list of chunks to skip as nessasary. Returns false on error.
|
||||
int add_skip_chunks(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag)
|
||||
int add_skip_chunks(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t offset, uint32_t flag)
|
||||
{
|
||||
|
||||
uint32_t value;
|
||||
int64_t result;
|
||||
uint64_t start = ctx->past;
|
||||
buffered_seek(ctx, (int)((offset*WTV_CHUNK_SIZE) - start));
|
||||
uint64_t seek_back=0-((offset*WTV_CHUNK_SIZE)-start);
|
||||
|
||||
uint32_t value;
|
||||
buffered_read(ctx, (unsigned char*)&value, 4);
|
||||
result = buffered_read(ctx, (unsigned char*)&value, 4);
|
||||
if(result!=4)
|
||||
return 0;
|
||||
seek_back-=4;
|
||||
while(value!=0)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "value: %llx\n", get_meta_chunk_start(value));
|
||||
buffered_read(ctx, (unsigned char*)&value, 4);
|
||||
result = buffered_read(ctx, (unsigned char*)&value, 4);
|
||||
if(result!=4)
|
||||
return 0;
|
||||
add_chunk(cb, get_meta_chunk_start(value));
|
||||
seek_back-=4;
|
||||
}
|
||||
buffered_seek(ctx, (int)seek_back);
|
||||
dbg_print(CCX_DMT_PARSE, "filebuffer_pos: %x\n", filebuffer_pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -96,7 +97,7 @@ void add_chunk(struct wtv_chunked_buffer *cb, uint64_t value)
|
||||
|
||||
// skip_sized_buffer. Same as get_sized_buffer, only without actually copying any data
|
||||
// in to the buffer.
|
||||
void skip_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
|
||||
void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
|
||||
{
|
||||
if(cb->buffer!=NULL && cb->buffer_size>0) {
|
||||
free(cb->buffer);
|
||||
@@ -121,47 +122,50 @@ void skip_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, u
|
||||
// get_sized_buffer will alloc and set a buffer in the passed wtv_chunked_buffer struct
|
||||
// it will handle any meta data chunks that need to be skipped in the file
|
||||
// Will print error messages and return a null buffer on error.
|
||||
void get_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
|
||||
void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size)
|
||||
{
|
||||
if(cb->buffer!=NULL && cb->buffer_size>0)
|
||||
int64_t result;
|
||||
if(cb->buffer != NULL && cb->buffer_size > 0)
|
||||
{
|
||||
free(cb->buffer);
|
||||
}
|
||||
if(size>WTV_MAX_ALLOC)
|
||||
|
||||
if(size > WTV_MAX_ALLOC)
|
||||
{
|
||||
mprint("\nRequested buffer of %i > %i bytes (WTV_MAX_ALLOC)!\n", size, WTV_MAX_ALLOC);
|
||||
cb->buffer=NULL;
|
||||
cb->buffer = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
cb->buffer = (uint8_t*)malloc(size);
|
||||
cb->buffer_size=size;
|
||||
cb->buffer_size = size;
|
||||
uint64_t start = cb->filepos;
|
||||
|
||||
if(cb->skip_chunks[cb->chunk]!=-1 && start+size>cb->skip_chunks[cb->chunk])
|
||||
if(cb->skip_chunks[cb->chunk] != -1 && (start + size) > cb->skip_chunks[cb->chunk])
|
||||
{
|
||||
buffered_read(ctx, cb->buffer, (int)(cb->skip_chunks[cb->chunk]-start));
|
||||
cb->filepos+=cb->skip_chunks[cb->chunk]-start;
|
||||
cb->filepos += cb->skip_chunks[cb->chunk]-start;
|
||||
buffered_seek(ctx, WTV_META_CHUNK_SIZE);
|
||||
cb->filepos+=WTV_META_CHUNK_SIZE;
|
||||
buffered_read(ctx, cb->buffer+(cb->skip_chunks[cb->chunk]-start), (int)(size-(cb->skip_chunks[cb->chunk]-start)));
|
||||
cb->filepos+=size-(cb->skip_chunks[cb->chunk]-start);
|
||||
cb->filepos += WTV_META_CHUNK_SIZE;
|
||||
result = buffered_read(ctx, cb->buffer+(cb->skip_chunks[cb->chunk]-start), (int)(size-(cb->skip_chunks[cb->chunk]-start)));
|
||||
cb->filepos += size-(cb->skip_chunks[cb->chunk]-start);
|
||||
cb->chunk++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read(ctx, cb->buffer, size);
|
||||
cb->filepos+=size;
|
||||
if(result!=size)
|
||||
result = buffered_read(ctx, cb->buffer, size);
|
||||
cb->filepos += size;
|
||||
if(result != size)
|
||||
{
|
||||
free(cb->buffer);
|
||||
cb->buffer_size=0;
|
||||
ctx->past=cb->filepos;
|
||||
cb->buffer=NULL;
|
||||
cb->buffer_size = 0;
|
||||
ctx->past = cb->filepos;
|
||||
cb->buffer = NULL;
|
||||
mprint("\nPremature end of file!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ctx->past=cb->filepos;
|
||||
ctx->past = cb->filepos;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -169,20 +173,20 @@ void get_sized_buffer(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, ui
|
||||
// the wtv header/root sections and calculate the skip_chunks.
|
||||
// If successful, will return with the file positioned
|
||||
// at the start of the data dir
|
||||
int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb)
|
||||
{
|
||||
int64_t result;
|
||||
ctx->startbytes_avail = (int)buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
|
||||
return_to_buffer(ctx->startbytes, ctx->startbytes_avail);
|
||||
return_to_buffer(ctx, ctx->startbytes, ctx->startbytes_avail);
|
||||
|
||||
uint8_t *parsebuf;
|
||||
parsebuf = (uint8_t*)malloc(1024);
|
||||
buffered_read(ctx, parsebuf,0x42);
|
||||
result = buffered_read(ctx, parsebuf,0x42);
|
||||
ctx->past+=result;
|
||||
if (result!=0x42)
|
||||
{
|
||||
mprint("\nPremature end of file!\n");
|
||||
end_of_file=1;
|
||||
return 0;
|
||||
return CCX_EOF;
|
||||
}
|
||||
// Expecting WTV header
|
||||
if( !memcmp(parsebuf, WTV_HEADER, 16 ) )
|
||||
@@ -192,8 +196,7 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
else
|
||||
{
|
||||
mprint("\nMissing WTV header. Abort.\n");
|
||||
end_of_file=1;
|
||||
return 0;
|
||||
return CCX_EOF;
|
||||
}
|
||||
|
||||
//Next read just enough to get the location of the root directory
|
||||
@@ -205,21 +208,18 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
dbg_print(CCX_DMT_PARSE, "root_dir: %x\n", root_dir);
|
||||
|
||||
//Seek to start of the root dir. Typically 0x1100
|
||||
buffered_skip(ctx, (root_dir*WTV_CHUNK_SIZE)-0x42);
|
||||
ctx->past+=(root_dir*WTV_CHUNK_SIZE)-0x42;
|
||||
result = buffered_skip(ctx,(root_dir*WTV_CHUNK_SIZE)-0x42);
|
||||
ctx->past += (root_dir*WTV_CHUNK_SIZE)-0x42;
|
||||
|
||||
if (result!=(root_dir*WTV_CHUNK_SIZE)-0x42)
|
||||
{
|
||||
end_of_file=1;
|
||||
return 0;
|
||||
}
|
||||
return CCX_EOF;
|
||||
|
||||
// Read and calculate the meta data chunks in the file we need to skip over
|
||||
// while parsing the file.
|
||||
int end=0;
|
||||
while(!end)
|
||||
{
|
||||
buffered_read(ctx, parsebuf, 32);
|
||||
result = buffered_read(ctx, parsebuf, 32);
|
||||
int x;
|
||||
for(x=0; x<16; x++)
|
||||
dbg_print(CCX_DMT_PARSE, "%02X ", parsebuf[x]);
|
||||
@@ -228,9 +228,8 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
if (result!=32)
|
||||
{
|
||||
mprint("\nPremature end of file!\n");
|
||||
end_of_file=1;
|
||||
free(parsebuf);
|
||||
return 0;
|
||||
return CCX_EOF;
|
||||
}
|
||||
ctx->past+=32;
|
||||
if( !memcmp(parsebuf, WTV_EOF, 16 ))
|
||||
@@ -250,17 +249,15 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
if(len>1024)
|
||||
{
|
||||
mprint("Too large for buffer!\n");
|
||||
end_of_file=1;
|
||||
free(parsebuf);
|
||||
return 0;
|
||||
return CCX_EOF;
|
||||
}
|
||||
buffered_read(ctx, parsebuf, len-32);
|
||||
result = buffered_read(ctx, parsebuf, len-32);
|
||||
if (result!=len-32)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
end_of_file=1;
|
||||
free(parsebuf);
|
||||
return 0;
|
||||
return CCX_EOF;
|
||||
}
|
||||
ctx->past+=len-32;
|
||||
// Read a unicode string
|
||||
@@ -287,9 +284,8 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
if(!add_skip_chunks(ctx, cb, value, flag))
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
end_of_file=1;
|
||||
free(parsebuf);
|
||||
return 0;
|
||||
return CCX_EOF;
|
||||
}
|
||||
}
|
||||
free(string);
|
||||
@@ -306,46 +302,52 @@ int read_header(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
|
||||
// Seek forward to the start of the data dir
|
||||
// Typically 0x40000
|
||||
buffered_skip(ctx, (int)((cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE)-ctx->past));
|
||||
cb->filepos=(cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE);
|
||||
result = buffered_skip(ctx,(int)((cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE)-ctx->past));
|
||||
cb->filepos = (cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE);
|
||||
cb->chunk++;
|
||||
ctx->past=cb->filepos;
|
||||
ctx->past = cb->filepos;
|
||||
free(parsebuf);
|
||||
return 1;
|
||||
return CCX_OK;
|
||||
}
|
||||
|
||||
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct demuxer_data *data)
|
||||
{
|
||||
static int video_streams[32];
|
||||
static int alt_stream; //Stream to use for timestamps if the cc stream has broken timestamps
|
||||
static int use_alt_stream = 0;
|
||||
static int num_streams=0;
|
||||
static int num_streams = 0;
|
||||
int64_t result;
|
||||
struct lib_cc_decode *dec_ctx = update_decoder_list(ctx);
|
||||
|
||||
while(1)
|
||||
{
|
||||
int bytesread = 0;
|
||||
// Read the 32 bytes containing the GUID and length and stream_id info
|
||||
get_sized_buffer(ctx, cb, 32);
|
||||
|
||||
if(cb->buffer==NULL) {end_of_file=1; return 0; } //Make this a macro?
|
||||
|
||||
uint8_t guid[16];
|
||||
memcpy(&guid, cb->buffer, 16); // Read the GUID
|
||||
int x;
|
||||
uint32_t len;
|
||||
uint32_t pad;
|
||||
uint32_t stream_id;
|
||||
|
||||
// Read the 32 bytes containing the GUID and length and stream_id info
|
||||
get_sized_buffer(ctx->demux_ctx, cb, 32);
|
||||
if(cb->buffer == NULL)
|
||||
return CCX_EOF;
|
||||
|
||||
memcpy(&guid, cb->buffer, 16); // Read the GUID
|
||||
|
||||
for(x=0; x<16; x++)
|
||||
dbg_print(CCX_DMT_PARSE, "%02X ", guid[x]);
|
||||
dbg_print(CCX_DMT_PARSE, "\n");
|
||||
uint32_t len;
|
||||
|
||||
memcpy(&len, cb->buffer+16, 4); // Read the length
|
||||
len-=32;
|
||||
dbg_print(CCX_DMT_PARSE, "len %X\n", len);
|
||||
uint32_t pad;
|
||||
pad = len%8==0 ? 0 : 8- (len % 8); // Calculate the padding to add to the length
|
||||
// to get to the next GUID
|
||||
dbg_print(CCX_DMT_PARSE, "pad %X\n", pad);
|
||||
uint32_t stream_id;
|
||||
memcpy(&stream_id, cb->buffer+20, 4);
|
||||
stream_id = stream_id & 0x7f; // Read and calculate the stream_id
|
||||
dbg_print(CCX_DMT_PARSE, "stream_id: %X\n", stream_id);
|
||||
dbg_print(CCX_DMT_PARSE, "stream_id: 0x%X\n", stream_id);
|
||||
|
||||
for(x=0; x<num_streams; x++)
|
||||
dbg_print(CCX_DMT_PARSE, "video stream_id: %X\n", video_streams[x]);
|
||||
@@ -354,30 +356,31 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
// This is the end of the data in this file
|
||||
// read the padding at the end of the file
|
||||
// and return one more byte
|
||||
dbg_print(CCX_DMT_PARSE, "WTV EOF\n");
|
||||
uint8_t *parsebuf;
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "WTV EOF\n");
|
||||
parsebuf = (uint8_t*)malloc(1024);
|
||||
do {
|
||||
buffered_read(ctx, parsebuf, 1024);
|
||||
ctx->past+=1024;
|
||||
result = buffered_read(ctx->demux_ctx, parsebuf, 1024);
|
||||
ctx->demux_ctx->past+=1024;
|
||||
} while (result==1024);
|
||||
ctx->past+=result;
|
||||
ctx->demux_ctx->past+=result;
|
||||
free(parsebuf);
|
||||
free(cb->buffer);
|
||||
cb->buffer=NULL;
|
||||
//return one more byte so the final percentage is shown correctly
|
||||
*(ctx->buffer+inbuf)=0x00;
|
||||
end_of_file=1;
|
||||
inbuf++;
|
||||
return 1;
|
||||
*(data->buffer+data->len)=0x00;
|
||||
data->len++;
|
||||
return CCX_EOF;
|
||||
}
|
||||
if( !memcmp(guid, WTV_STREAM2, 16 ) )
|
||||
{
|
||||
// The WTV_STREAM2 GUID appares near the start of the data dir
|
||||
// It maps stream_ids to the type of stream
|
||||
dbg_print(CCX_DMT_PARSE, "WTV STREAM2\n");
|
||||
get_sized_buffer(ctx, cb, 0xc+16);
|
||||
if(cb->buffer==NULL) {end_of_file=1; return 0; }
|
||||
get_sized_buffer(ctx->demux_ctx, cb, 0xc+16);
|
||||
if(cb->buffer==NULL)
|
||||
return CCX_EOF;
|
||||
static unsigned char stream_type[16];
|
||||
memcpy(&stream_type, cb->buffer+0xc, 16); //Read the stream type GUID
|
||||
const void *stream_guid;
|
||||
@@ -397,18 +400,19 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
if (!memcmp(guid, WTV_TIMING, 16) && ((use_alt_stream < WTV_CC_TIMESTAMP_MAGIC_THRESH && check_stream_id(stream_id, video_streams, num_streams))
|
||||
|| (use_alt_stream == WTV_CC_TIMESTAMP_MAGIC_THRESH && stream_id == alt_stream)))
|
||||
{
|
||||
int64_t time;
|
||||
// The WTV_TIMING GUID contains a timestamp for the given stream_id
|
||||
dbg_print(CCX_DMT_PARSE, "WTV TIMING\n");
|
||||
get_sized_buffer(ctx, cb, 0x8+0x8);
|
||||
if(cb->buffer==NULL) {end_of_file=1; return 0; }
|
||||
int64_t time;
|
||||
get_sized_buffer(ctx->demux_ctx, cb, 0x8+0x8);
|
||||
if(cb->buffer==NULL)
|
||||
return CCX_EOF;
|
||||
|
||||
memcpy(&time, cb->buffer+0x8, 8); // Read the timestamp
|
||||
dbg_print(CCX_DMT_PARSE, "TIME: %ld\n", time);
|
||||
if (time != -1 && time != WTV_CC_TIMESTAMP_MAGIC) { // Ignore -1 timestamps
|
||||
current_pts = time_to_pes_time(time); // Convert from WTV to PES time
|
||||
pts_set = 1;
|
||||
set_current_pts(dec_ctx->timing, time_to_pes_time(time));
|
||||
frames_since_ref_time = 0;
|
||||
set_fts();
|
||||
set_fts(dec_ctx->timing);
|
||||
}
|
||||
else if (time == WTV_CC_TIMESTAMP_MAGIC && stream_id != alt_stream) {
|
||||
use_alt_stream++;
|
||||
@@ -419,21 +423,22 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
len-=16;
|
||||
}
|
||||
if( !memcmp(guid, WTV_DATA, 16 )
|
||||
&& check_stream_id(stream_id, video_streams, num_streams) && current_pts!=0
|
||||
&& check_stream_id(stream_id, video_streams, num_streams) && dec_ctx->timing->current_pts != 0
|
||||
&& (ccx_options.wtvmpeg2 || (!ccx_options.wtvmpeg2 && len==2)))
|
||||
{
|
||||
// This is the data for a stream we want to process
|
||||
dbg_print(CCX_DMT_PARSE, "\nWTV DATA\n");
|
||||
get_sized_buffer(ctx, cb, len);
|
||||
if(cb->buffer==NULL) {end_of_file=1; return 0; }
|
||||
memcpy(ctx->buffer+inbuf, cb->buffer, len);
|
||||
inbuf+=result;
|
||||
get_sized_buffer(ctx->demux_ctx, cb, len);
|
||||
if(cb->buffer==NULL)
|
||||
return CCX_EOF;
|
||||
memcpy(data->buffer+data->len, cb->buffer, len);
|
||||
data->len += len;
|
||||
bytesread+=(int) len;
|
||||
frames_since_ref_time++;
|
||||
set_fts();
|
||||
set_fts(dec_ctx->timing);
|
||||
if(pad>0)
|
||||
{ //Make sure we skip any padding too, since we are returning here
|
||||
skip_sized_buffer(ctx, cb, pad);
|
||||
skip_sized_buffer(ctx->demux_ctx, cb, pad);
|
||||
}
|
||||
return bytesread;
|
||||
}
|
||||
@@ -442,26 +447,52 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb)
|
||||
// skip any remaining data
|
||||
// For any unhandled GUIDs this will be len+pad
|
||||
// For others it will just be pad
|
||||
skip_sized_buffer(ctx, cb, len+pad);
|
||||
skip_sized_buffer(ctx->demux_ctx, cb, len+pad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLONG wtv_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
int wtv_getmoredata(struct lib_ccx_ctx *ctx, struct demuxer_data ** ppdata)
|
||||
{
|
||||
static struct wtv_chunked_buffer cb;
|
||||
if(firstcall)
|
||||
{
|
||||
init_chunked_buffer(&cb);
|
||||
if(ccx_options.wtvmpeg2)
|
||||
ccx_bufferdatatype=CCX_PES;
|
||||
else
|
||||
ccx_bufferdatatype=CCX_RAW;
|
||||
if(read_header(ctx, &cb)==0)
|
||||
// read_header returned an error
|
||||
// read_header will have printed the error message
|
||||
return 0;
|
||||
firstcall=0;
|
||||
}
|
||||
return get_data(ctx, &cb);
|
||||
int ret = CCX_OK;
|
||||
struct demuxer_data *data;
|
||||
|
||||
if(!*ppdata)
|
||||
{
|
||||
*ppdata = alloc_demuxer_data();
|
||||
if(!*ppdata)
|
||||
return -1;
|
||||
data = *ppdata;
|
||||
//TODO Set to dummy, find and set actual value
|
||||
data->program_number = 1;
|
||||
data->stream_pid = 1;
|
||||
data->codec = CCX_CODEC_ATSC_CC;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = *ppdata;
|
||||
}
|
||||
|
||||
if(firstcall)
|
||||
{
|
||||
init_chunked_buffer(&cb);
|
||||
|
||||
if(ccx_options.wtvmpeg2)
|
||||
data->bufferdatatype=CCX_PES;
|
||||
else
|
||||
data->bufferdatatype=CCX_RAW;
|
||||
|
||||
read_header(ctx->demux_ctx, &cb);
|
||||
if(ret != CCX_OK)
|
||||
{
|
||||
// read_header returned an error
|
||||
// read_header will have printed the error message
|
||||
return ret;
|
||||
}
|
||||
firstcall=0;
|
||||
}
|
||||
ret = get_data(ctx, &cb, data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
14
src/win_iconv/iconv.h
Executable file
14
src/win_iconv/iconv.h
Executable file
@@ -0,0 +1,14 @@
|
||||
#ifndef _LIBICONV_H
|
||||
#define _LIBICONV_H
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef void* iconv_t;
|
||||
iconv_t iconv_open(const char *tocode, const char *fromcode);
|
||||
int iconv_close(iconv_t cd);
|
||||
size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
4145
src/win_iconv/win_iconv.h → src/win_iconv/win_iconv.c
Normal file → Executable file
4145
src/win_iconv/win_iconv.h → src/win_iconv/win_iconv.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -42,6 +42,7 @@
|
||||
<ClInclude Include="..\src\libpng\pngpriv.h" />
|
||||
<ClInclude Include="..\src\libpng\pngstruct.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\608_spupng.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\avc_functions.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_common_char_encoding.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_common_common.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_common_constants.h" />
|
||||
@@ -50,7 +51,10 @@
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_common_timing.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_608.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_encoding.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_output.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_common.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_isdb.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_structs.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_xds.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_encoders_common.h" />
|
||||
@@ -61,6 +65,7 @@
|
||||
<ClInclude Include="..\src\lib_ccx\lib_ccx.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\spupng_encoder.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\teletext.h" />
|
||||
<ClInclude Include="..\src\lib_ccx\utility.h" />
|
||||
<ClInclude Include="..\src\zlib\crc32.h" />
|
||||
<ClInclude Include="..\src\zlib\deflate.h" />
|
||||
<ClInclude Include="..\src\zlib\gzguts.h" />
|
||||
@@ -134,11 +139,6 @@
|
||||
<ClCompile Include="..\src\libpng\pngwrite.c" />
|
||||
<ClCompile Include="..\src\libpng\pngwtran.c" />
|
||||
<ClCompile Include="..\src\libpng\pngwutil.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\608_sami.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\608_smptett.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\608_spupng.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\608_srt.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\708_encoding.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\activity.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\asf_functions.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\avc_functions.c" />
|
||||
@@ -149,10 +149,21 @@
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_common_timing.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_608.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_encoding.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_output.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_common.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_isdb.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_xds.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_demuxer.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_dtvcc.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_common.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_helpers.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_sami.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_smptett.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_spupng.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_srt.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_webvtt.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_xds.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\cc_bitstream.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\configuration.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\dvb_subtitle_decoder.c" />
|
||||
@@ -172,10 +183,12 @@
|
||||
<ClCompile Include="..\src\lib_ccx\stream_functions.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\telxcc.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_functions.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_info.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_tables.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_tables_epg.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\utility.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\wtv_functions.c" />
|
||||
<ClCompile Include="..\src\win_iconv\win_iconv.c" />
|
||||
<ClCompile Include="..\src\zlib\adler32.c" />
|
||||
<ClCompile Include="..\src\zlib\crc32.c" />
|
||||
<ClCompile Include="..\src\zlib\deflate.c" />
|
||||
@@ -193,7 +206,7 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
|
||||
@@ -240,6 +240,21 @@
|
||||
<ClInclude Include="..\src\lib_ccx\lib_ccx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_encoding.h">
|
||||
<Filter>Header Files\ccx_decoders</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_708_output.h">
|
||||
<Filter>Header Files\ccx_decoders</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\lib_ccx\ccx_decoders_isdb.h">
|
||||
<Filter>Header Files\ccx_decoders</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\lib_ccx\avc_functions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\lib_ccx\utility.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\ccextractor.c">
|
||||
@@ -533,21 +548,6 @@
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_common_timing.c">
|
||||
<Filter>Source Files\ccx_common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\608_sami.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\608_smptett.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\608_spupng.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\608_srt.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\708_encoding.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_common.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
@@ -566,5 +566,56 @@
|
||||
<ClCompile Include="..\src\lib_ccx\ts_tables_epg.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_demuxer.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ts_info.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_encoding.c">
|
||||
<Filter>Source Files\ccx_decoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_dtvcc.c">
|
||||
<Filter>Source Files\ccx_decoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_output.c">
|
||||
<Filter>Source Files\ccx_decoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\win_iconv\win_iconv.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_encoding.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_708_output.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_dtvcc.c">
|
||||
<Filter>Source Files\ccx_decoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\win_iconv\win_iconv.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_sami.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_smptett.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_spupng.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_srt.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_webvtt.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_encoders_xds.c">
|
||||
<Filter>Source Files\ccx_encoders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\lib_ccx\ccx_decoders_isdb.c">
|
||||
<Filter>Source Files\ccx_decoders</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user