Compare commits

..

329 Commits
v0.70 ... v0.76

Author SHA1 Message Date
cfsmp3
4f3e5fe677 0.76 2015-03-28 13:32:09 +01:00
cfsmp3
ad99ccdfec Merge branch 'pr/n143_hardikchoudhary12' 2015-03-23 13:06:32 +01:00
cfsmp3
1bc174efa2 Merge branch 'pr/n144_ivladak' 2015-03-23 13:05:50 +01:00
cfsmp3
983db8c92d Allow processing EPG only 2015-03-23 13:05:10 +01:00
Vladislav Ivanishin
b4ce115f7c Fixed mac build 2015-03-21 04:26:49 +03:00
hardikchoudhary12
cb7f31ef8c Update README.md
Updated grammar.
2015-03-17 04:00:55 +05:30
cfsmp3
1a5d78b1b4 Merge branch 'pr/n138_brooss' 2015-03-04 09:38:22 +01:00
Brooss
c873ff6a06 add -xmltvonlycurrent option 2015-03-04 15:53:16 +11:00
Brooss
454024808d escape XML strings 2015-03-03 15:56:24 +11:00
Brooss
0a22e1e429 fix crash with -out=null 2015-03-03 14:38:19 +11:00
Brooss
3fb288357d change parse_EPG_packet to void 2015-03-03 12:27:28 +11:00
Brooss
966d88fc10 fix gcc warnings 2015-03-03 12:12:40 +11:00
Brooss
c91aa79852 rename win_iconv.c -> win_iconv.h, fixes build script 2015-03-03 12:06:07 +11:00
cfsmp3
04ccb477f1 -stdin was broken, fixed. 2015-03-02 09:48:55 +01:00
cfsmp3
10ea570229 Merge branch 'pr/n137_brooss' 2015-03-02 07:14:45 +01:00
Brooss
551c3d0e2f Fix referencing outdated offset in EPG_decode_extended_event_descriptor 2015-03-02 13:00:28 +11:00
cfsmp3
49530b079b Merge branch 'pr/n137_brooss' 2015-03-01 18:40:15 +01:00
Brooss
02986fe7a8 fix buffer overrun in EPG_decode_extended_event_descriptor 2015-03-02 04:18:36 +11:00
cfsmp3
a230ec5f6f Merge branch 'pr/n135_brooss' 2015-03-01 17:03:24 +01:00
Brooss
7902b85d1b Fix codepage symbol getting letf in the middle of certain dvb extented_event_descriptor strings 2015-03-02 02:24:18 +11:00
Brooss
77d275d6a5 fix ratings closings tag 2015-03-02 01:48:54 +11:00
Brooss
4c2a4a59a2 Add fallback workaround for streams with no PMT but EPG 2015-03-02 00:49:13 +11:00
cfsmp3
d80455a408 Merge branch 'pr/n134_mailumangjain' 2015-03-01 09:12:33 +01:00
cfsmp3
27e2bb9017 fix for broken stdout 2015-03-01 09:12:12 +01:00
Umang Jain
9358978a61 Fixes output for field_2 2015-02-27 20:47:50 +05:30
Brooss
cffd02c106 string formatting in EPG_print_event fix 2015-02-26 14:25:57 +11:00
cfsmp3
b45370cbb4 Minor typo correction 2015-02-25 08:43:06 +01:00
Brooss
56e15a3be0 Call iconv_close. Fix warning 2015-02-25 16:48:40 +11:00
Brooss
7b4d93988f Fixes for compiling on MSVC2013 2015-02-25 16:37:57 +11:00
Umang Jain
0e803eba95 Fix for SegFault error in -out=raw/bin output format
Issue Link:https://github.com/CCExtractor/ccextractor/issues/102
2015-02-24 18:58:54 +05:30
Brooss
8c9bfa17dd fix fprintf formatting in EPG_print_event() 2015-02-16 11:46:55 +11:00
Brooss
413173f5e5 add public domain win_iconv for win32 2015-02-16 11:28:49 +11:00
Brooss
1a050c76a5 Inital DVB and ATSC EPG support 2015-02-16 11:06:51 +11:00
cfsmp3
c3d00d80f5 Added support for M2TS 2015-02-10 17:27:17 +01:00
cfsmp3
c989c941df Added dates to CHANGES.TXT 2015-01-22 13:50:04 +01:00
cfsmp3
dc9f6d250a Fix annoying warning in OSX build 2015-01-18 22:56:26 +01:00
cfsmp3
9f00cec9c0 Uncomment a condition in es_functions that was causing garbled output (unknown why we commeted it out in the first place) 2015-01-10 17:57:16 +01:00
cfsmp3
b7d2754518 Merge branch 'pr/n130_anshul1912' 2015-01-09 13:29:33 +01:00
Anshul Maheshwari
94675b2dac handle no language found 2015-01-09 13:14:32 +01:00
Anshul Maheshwari
2c9faa70ea give error message with ENABLE_OCR 2015-01-07 19:57:57 +01:00
cfsmp3
b7616fcb17 Merge branch 'pr/n130_anshul1912' 2015-01-07 16:32:30 +01:00
Anshul Maheshwari
eb93345544 added dirent.h 2015-01-07 20:44:47 +05:30
cfsmp3
e6024c1cb1 Merge branch 'pr/n129_anshul1912' 2015-01-07 15:16:23 +01:00
Anshul Maheshwari
ecc4c2520e assigning prev_start to start_time 2015-01-07 19:38:55 +05:30
Anshul Maheshwari
a83c686f6a Remove multi warning when traindata not present 2015-01-07 18:49:53 +05:30
Anshul Maheshwari
c4a8135b4d using language while opening traindata
Signed-off-by: Anshul Maheshwari <anshul.ffmpeg@gmail.com>
2015-01-07 14:45:47 +05:30
cfsmp3
004f9d512a Typos 2015-01-07 10:01:39 +01:00
cfsmp3
53df68b4c3 Merge branch 'pr/n128_anshul1912' 2015-01-06 21:40:30 +01:00
Anshul Maheshwari
74bb91aa5b fixing minor bugs 2015-01-06 21:19:39 +05:30
rkuchumov
453bb56520 stdout output fix 2015-01-01 10:55:26 +03:00
cfsmp3
db50730a00 Fixed typos in docs 2014-12-25 12:17:34 +01:00
Anshul Maheshwari
36a266e43c Merge branch 'master' of https://github.com/anshul1912/ccextractor 2014-12-24 11:58:32 +05:30
Anshul Maheshwari
354c52ec61 updated teletext changes 2014-12-24 11:53:00 +05:30
Anshul Maheshwari
2b65419bfb Merge remote-tracking branch 'carlos/master' 2014-12-24 11:47:07 +05:30
cfsmp3
740365db7e Merge branch 'pr/n125_MikaYuoadas' 2014-12-23 12:44:45 +01:00
cfsmp3
03dc0498ea Init 'ret' variables 2014-12-23 12:43:47 +01:00
Akim Sadaoui
e9a7474f3d Fixed potential timestamp overflow with negative delay
When delay was a large enough negative number, some show_timestamp would
overflow and be set to ridiculously large value.
2014-12-19 17:00:12 +01:00
Akim Sadaoui
1ecb2abd62 Added support for -startat and -endat for teletext input 2014-12-19 16:59:23 +01:00
Akim Sadaoui
d3b4b8ff03 Fixed smptett timeExpression format
Now all timeExperssion in smptett file comply to:
http://www.w3.org/TR/2013/REC-ttml1-20130924/#timing-value-timeExpression
2014-12-19 16:55:47 +01:00
Akim Sadaoui
29aa63c23c Fixed a typo in smptett header 2014-12-19 16:50:21 +01:00
Anshul Maheshwari
7083a36ecb Merge remote-tracking branch 'carlos/master' 2014-11-30 21:09:40 +05:30
Anshul Maheshwari
38421e886e Merge remote-tracking branch 'carlos/master' 2014-11-28 19:42:19 +01:00
Akim Sadaoui
b0de53c351 Added default style to smptett header 2014-11-28 15:57:50 +01:00
Akim Sadaoui
09dcb8b7c0 Fixed a rare bug with some teletext input
In rare cases, the output had the last line written after the footer (i.e. for
smptett the last </div></tt> was after the last <p>).
2014-11-28 15:56:28 +01:00
Akim Sadaoui
13ab9e6a4e Fixed line break in output for teletext input 2014-11-28 15:56:06 +01:00
Akim Sadaoui
08ae34bc24 Added smptett support for teletext input 2014-11-28 15:54:40 +01:00
Akim Sadaoui
f5f1a70eb8 fixed a typo in generated smptett 2014-11-28 15:54:35 +01:00
Anshul Maheshwari
471c130928 updated version to 0.75 2014-11-26 18:31:01 +05:30
cfsmp3
4db37e7ac3 Merge branch 'pr/n121_anshul1912' 2014-11-26 13:57:53 +01:00
Anshul Maheshwari
3953f806b0 corrected sign of argument 2014-11-26 18:02:25 +05:30
Anshul Maheshwari
cf0ebd27f7 corrected initial value of ret 2014-11-26 18:00:53 +05:30
Anshul Maheshwari
559d05c478 added flag in CCExtractor Cmake to build with FFMpeg 2014-11-26 17:58:49 +05:30
Anshul Maheshwari
4d7e629ba5 in ffmpeg intigration logic, removed unneeded malloc and free 2014-11-26 17:57:41 +05:30
Anshul Maheshwari
866c4ea159 added flag in CCExtractor Cmake to build with FFMpeg 2014-11-26 17:55:20 +05:30
Anshul Maheshwari
cf508653f2 documented how to compile ccextractor with FFmpeg using cmake 2014-11-26 17:53:12 +05:30
Anshul Maheshwari
b3b683aa83 Instruction on how to build ccextractor with CMake 2014-11-25 15:00:39 +05:30
Anshul Maheshwari
9f6309ef14 More elaborate warning for DVB subtitle's 2014-11-14 18:12:48 +05:30
cfsmp3
b95e06c21c Merge branch 'pr/n118_anshul1912' 2014-11-11 13:35:37 +01:00
Anshul Maheshwari
7ed99097ba removed libpng15 requirement in cmake 2014-10-31 04:44:38 +05:30
Anshul Maheshwari
3f4bbbde25 addd some platform specific library path 2014-10-31 04:38:06 +05:30
Anshul Maheshwari
5828f50210 init timing while initilaizing library 2014-10-31 04:19:53 +05:30
Anshul Maheshwari
b5931e8749 added dinit function to remove some memory leaks 2014-10-29 21:23:41 +05:30
Anshul Maheshwari
c588b42e0a remove redundant write format 2014-10-20 04:06:51 +05:30
Anshul Maheshwari
f9ee9570a4 remove internal use of ccx_decoders_common_settings_t 2014-10-20 03:16:57 +05:30
Anshul Maheshwari
55e408bbb7 made seprate decoder context 2014-10-19 22:36:02 +05:30
Anshul Maheshwari
93a5ae9728 cmake:generate pkg-config pc file on make install 2014-10-17 22:02:08 +05:30
cfsmp3
5c7430cff5 Merge branch 'pr/n116_anshul1912' 2014-10-12 09:56:02 +02:00
cfsmp3
fecf14bc15 Merge branch 'pr/n117_wforums' 2014-10-12 09:55:18 +02:00
wforums
a4275eba62 MAC build command fix
Fixed.
2014-10-12 00:47:47 +02:00
wforums
3873e8fd30 Bugfix for output filename fix
Getting tired :( Forgot to change header.
2014-10-12 00:45:08 +02:00
Anshul Maheshwari
5e22be2576 reverted back the changes of adding exra byte 2014-10-12 03:56:00 +05:30
cfsmp3
0b568cb168 Merge branch 'pr/n115_wforums' 2014-10-11 22:53:25 +02:00
cfsmp3
017d539710 Merge branch 'pr/n114_anshul1912' 2014-10-11 22:52:40 +02:00
wforums
06c8f69056 Output filename fix
The provided names in -o1 and -o2 were not passed on between argument
passing and initialisation of write structures, resulting in default
names.
2014-10-11 22:47:16 +02:00
Anshul Maheshwari
b06654b760 increased 1 byte of cc_data according to spec
According to CEA-708-D August 2008
cc_data() {
    reserved                   1 bit
    proccess_cc_data_flag      1 bit
    zero bit                   1 bit
    cc_count                   5 bit
    reserved                   8 bit
    for( i = 0; i < cc_count; i++) {
        one_bit_4_compatibility      1 bit
        reserved                     4 bit
        cc_valid                     1 bit
        cc_type                      2 bit
        cc_data_1                    8 bit
        cc_data_2                    8 bit
    }
}
2014-10-12 00:55:08 +05:30
cfsmp3
4ff49c2010 Merge branch 'pr/n113_anshul1912' 2014-10-11 13:02:11 +02:00
Anshul Maheshwari
0c650711cf corrected ffmpeg enabled build 2014-10-11 14:54:02 +05:30
cfsmp3
3128f10fb5 In srt, use -lf to change CRLF for LF. 2014-10-11 11:23:18 +02:00
cfsmp3
63b209929e Version push (to 0.75) 2014-10-11 10:48:12 +02:00
cfsmp3
5f68a9166f -Added -bom 2014-10-11 10:39:56 +02:00
Anshul Maheshwari
15616edea8 updated changes 2014-10-11 12:26:54 +05:30
cfsmp3
cce4ec5e1a Merge branch 'pr/n111_wforums' 2014-10-11 08:05:02 +02:00
Anshul Maheshwari
72ecd279cf passing ctx to store_hdcc 2014-10-11 10:47:06 +05:30
Anshul Maheshwari
87f1a3845c remove more global variables from header files 2014-10-11 02:25:58 +05:30
Anshul Maheshwari
4ae5f3483c removed global variable from header files 2014-10-11 01:48:57 +05:30
Anshul Maheshwari
38876690f8 Merge branch 'master' of https://github.com/anshul1912/ccextractor 2014-10-10 23:57:55 +05:30
Anshul Maheshwari
7bb4e842dd corrected function declaration 2014-10-10 23:56:53 +05:30
wforums
26d9584a93 Windows projext fix 2014-10-10 18:49:46 +02:00
wforums
9d5ce9aaae UCLA bug fix?
-
2014-10-10 18:49:39 +02:00
wforums
47264425df Fix of build script + moving ccfont2 2014-10-10 16:47:30 +02:00
wforums
e8f8d04369 possible fix for ucla timing issue 2014-10-10 16:37:41 +02:00
Anshul Maheshwari
78cb26c9cb moved windows specific include 2014-10-09 20:20:23 -07:00
Anshul Maheshwari
2f5d45df01 added library file in windows build script 2014-10-09 18:49:02 -07:00
wforums
53be44dfdb Merge branch 'master' of https://github.com/CCExtractor/ccextractor 2014-10-09 23:12:13 +02:00
wforums
48b5a0b384 Small UCLA fix
-
2014-10-09 23:12:07 +02:00
Anshul Maheshwari
a08c7b1871 corrected do_NAL declaration 2014-10-09 16:15:13 +05:30
Anshul Maheshwari
0a2a00f883 corrected pointer 2014-10-09 15:36:46 +05:30
Anshul Maheshwari
2125e58e1f minor refactoring to correctly set options 2014-10-09 15:04:17 +05:30
Anshul Maheshwari
5bdd6971f7 moved option parsing in library 2014-10-08 18:48:16 +05:30
Anshul Maheshwari
051bc7138d moved global variable in library context 2014-10-08 18:44:07 +05:30
Anshul Maheshwari
e6dca329ee removed option parameter from ccextractor 2014-10-07 21:43:00 +05:30
Anshul Maheshwari
6cfddb12a6 corrected typo cxx to ccx 2014-10-07 19:56:35 +05:30
Anshul Maheshwari
c9c063b8d8 Merge -xds willem changes 2014-10-07 19:50:02 +05:30
Anshul Maheshwari
e0cd8b2e56 builds on windows 2014-10-07 19:25:09 -07:00
Anshul Maheshwari
38d2088db5 include lib_ccx.h instead of ccextractor.h 2014-10-07 16:35:30 +05:30
Anshul Maheshwari
8e940b050a rename ccextractor.h to lib_ccx.h 2014-10-07 16:25:14 +05:30
cfsmp3
5733b40ca6 Merge branch 'pr/n107_anshul1912' 2014-10-07 12:03:51 +02:00
cfsmp3
22c40675a6 Merge branch 'pr/n108_wforums' 2014-10-07 12:00:36 +02:00
wforums
a3ef46c21d XDS fix + exception when parameters not compatible
See title :)
2014-10-07 11:34:09 +02:00
Anshul Maheshwari
93a546bab4 compiled on windows 2014-10-07 00:24:45 -07:00
Anshul Maheshwari
ec427fd82c remove use of relative path 2014-10-07 00:21:28 -07:00
Anshul Maheshwari
70cc3c2046 Added Cmake support 2014-10-07 02:39:41 +05:30
Anshul Maheshwari
5634960813 add ccx library path in Makefile 2014-10-07 02:39:36 +05:30
Anshul Maheshwari
c7a49e80e3 relative paths while including header file 2014-10-07 02:39:31 +05:30
Anshul Maheshwari
617d2d30dc move all code except ccextractor in folder lib_ccx 2014-10-07 02:38:54 +05:30
cfsmp3
18f781d099 0.74 2014-09-24 13:04:26 +02:00
Ruslan Kuchumov
84db812769 windows support 2014-09-08 18:49:37 +00:00
Ruslan Kuchumov
7763f8aeab pointer bugfix 2014-09-08 18:02:49 +00:00
Ruslan Kuchumov
faa879801e printing output on SIGINT 2014-09-08 09:02:10 +00:00
wforums
4635329a5b Changes.txt updated
-
2014-09-06 13:17:04 +02:00
wforums
b89cc3b6df UCLA TT format change
Switched around TEL & TT page number in ttxt format.
2014-09-06 13:16:51 +02:00
wforums
e9f8313f7c BOM parameter
BOM can be not written now if -nobom is passed as parameter.
2014-09-06 13:16:25 +02:00
wforums
324cd84ffe UCLA parameter fix
Added a new option to ensure that UCLA parameter doesn't get overriden
anymore.
2014-09-06 12:13:50 +02:00
wforums
9d7518c9ec -o1 -o2 -12 fix
Fixes the issue where when using multiple output files, everyting is
written to the -o2 output file.
2014-09-06 00:07:28 +02:00
Ruslan Kuchumov
32e0d6023d sending teletext to the server 2014-09-04 16:07:06 +00:00
Ruslan Kuchumov
c9465e476b segfault when no input files bugfix 2014-09-04 16:02:51 +00:00
Ruslan Kuchumov
45d237da40 removed bin output when sending to server 2014-09-04 15:33:02 +00:00
cfsmp3
631ae2e02f Version bump (0.72 to 0.73) 2014-08-19 07:45:00 +02:00
Anshul Maheshwari
695aa14cd7 Merge remote-tracking branch 'carlos/master' 2014-08-18 23:47:03 +05:30
Anshul Maheshwari
b638bb1d3a updated some grammer in Readme.md 2014-08-18 23:37:03 +05:30
Anshul Maheshwari
28950bf90e changes should not be in Readme.md 2014-08-18 23:22:43 +05:30
wforums
77f8289ca6 Version change
- Added description
2014-08-18 14:26:52 +02:00
wforums
cece92a828 Merge conflict resolve
Fixed merge conflicts
2014-08-18 13:50:30 +02:00
wforums
bd08454d66 Merge from upstream 2014-08-18 13:45:44 +02:00
wforums
c6e5dd5cf7 GPACMP4 filter
moved 2 files to filter
2014-08-18 13:43:12 +02:00
cfsmp3
bd8e3ad137 Merge branch 'pr/n98_rkuchumov' 2014-08-18 13:34:31 +02:00
cfsmp3
8a2e71fcfb Merge branch 'pr/n99_rkuchumov' 2014-08-18 13:33:06 +02:00
wforums
301c2a7138 Library - step one and half
- moved around some functions
- 608_helpers is gone now (moved last function)
2014-08-18 10:35:43 +02:00
Anshul Maheshwari
5368d7292f update version 2014-08-18 13:13:54 +05:30
Anshul Maheshwari
29689b10aa Merge branch 'master' of https://github.com/anshul1912/ccextractor 2014-08-18 13:11:03 +05:30
Anshul Maheshwari
4d8883d0f1 Documented FFmpeg Intigration 2014-08-18 13:10:06 +05:30
Anshul Maheshwari
efe6fceb3a add cflags for gpacmp4 on linux 2014-08-17 10:19:54 +02:00
Ruslan Kuchumov
d9a998b95f memory leak 2014-08-16 23:53:34 +00:00
Ruslan Kuchumov
bf94c2997d unusable variable 2014-08-16 23:41:14 +00:00
Ruslan Kuchumov
6405a3973d tlt support 2014-08-16 21:53:00 +00:00
Anshul Maheshwari
9270e22a65 Merge branch 'master' of https://github.com/anshul1912/ccextractor 2014-08-16 09:49:32 +02:00
Anshul Maheshwari
02e19cf617 corrected CFLAGS to be include in ffmpeg enable 2014-08-16 09:48:29 +02:00
Ruslan Kuchumov
1493b6c4f5 renaming 2014-08-15 21:29:28 +00:00
wforums
74ab732999 Library - fixes
-
2014-08-15 18:37:15 +02:00
wforums
5961d1b56e Library - fixes
-
2014-08-15 18:24:17 +02:00
wforums
87d6a6bf91 Library - fixes
Include fixes
2014-08-15 18:19:48 +02:00
wforums
456d23f547 Library - step one and half
- Cleaned out header files + adjusted accordingly
- Decoupled spupng_encoder from ccextractor.h
- Decoupled ccx_encoders_common from ccextractor.h
2014-08-15 17:47:58 +02:00
wforums
02da93d0e4 Merge conflict fix
-
2014-08-15 14:09:33 +02:00
wforums
597304e932 Merge from upstream
-
2014-08-15 12:34:18 +02:00
Anshul Maheshwari
918889c890 corrected timing in spupng xml file 2014-08-15 12:28:30 +02:00
Anshul Maheshwari
47bfe6bffc corrected timing for tudor using ffmpeg 2014-08-15 12:28:29 +02:00
cfsmp3
5789a0a224 Updated MD 2014-08-15 12:28:29 +02:00
Anshul Maheshwari
b15f54c7f9 Intigration of ffmpeg in ccextractor 2014-08-15 12:28:28 +02:00
wforums
bc3794eb14 Library - step one and hafl
-
2014-08-15 11:59:53 +02:00
wforums
4e66d290a6 Library - step one and half
Moved most of 608_helper functions to ccx_encoders_helpers, as they seem
more logical. No idea yet where the last one has to go (used in both
encoder/decoder 608 right now)
2014-08-15 11:44:14 +02:00
wforums
7b48b01fd1 Library - intermediate
This one has errors!
2014-08-15 09:00:16 +02:00
Anshul Maheshwari
883dfaae4a corrected timing in spupng xml file 2014-08-14 20:45:38 +05:30
wforums
884a25a7cd Commented unused vars
Added a ; too much.
2014-08-13 15:54:27 +02:00
wforums
8cc8767634 Commented unused variables
-
2014-08-13 15:48:08 +02:00
wforums
90a6902ad4 Library - step one and half
More removal of links.
2014-08-13 15:47:53 +02:00
wforums
b334acb426 Library - step one and half
Decoupled 708 from ccextractor.h (finally), reworked some things as
well.
2014-08-13 15:33:51 +02:00
Anshul Maheshwari
9c847aa4f1 Merge remote-tracking branch 'carlos/master' 2014-08-13 17:48:50 +05:30
Anshul Maheshwari
c3397d1949 corrected timing for tudor using ffmpeg 2014-08-13 17:48:00 +05:30
Ruslan Kuchumov
41ad0b4006 cc_name 2014-08-12 22:32:11 +00:00
cfsmp3
7fa59a14f7 Updated MD 2014-08-12 17:15:39 +02:00
wforums
170a57b9c6 Library - fix
-
2014-08-12 14:34:34 +02:00
wforums
0a15c2d16e Library - fix
Fix of includes
2014-08-12 14:32:28 +02:00
wforums
c52283676a Library - step one and half
- Moved enum & struct to more appropriate place (also fixes error with
compiling under linux)
2014-08-12 14:26:48 +02:00
wforums
ce3c2b5ae2 Merge fix 2
-
2014-08-12 12:25:35 +02:00
wforums
48e030d94c Merge fix
Fixing errors that popped up after trying to merge.
2014-08-12 12:14:36 +02:00
wforums
afaa7c8b76 Merge try
Trying to merge
2014-08-12 11:41:22 +02:00
wforums
4e6c0352b0 XDS segfault fix
Fixes segfault on using TTXT + XDS
2014-08-12 10:39:01 +02:00
Anshul Maheshwari
f84b69aca7 Intigration of ffmpeg in ccextractor 2014-08-12 10:43:07 +05:30
cfsmp3
cc7ebbc4d7 Replace g++ with gcc in OSX 2014-08-11 14:33:52 +02:00
Ruslan Kuchumov
7a74b815fa segfault on error fix 2014-08-09 21:23:27 +00:00
Ruslan Kuchumov
331038634d password bug fix 2014-08-09 21:17:41 +00:00
Ruslan Kuchumov
aa2c316093 Chris's patch 2014-08-09 20:52:15 +00:00
cfsmp3
3347f5d345 Version bump 2014-08-09 13:18:56 +02:00
cfsmp3
141792a299 Delete upgradelog. 2014-08-09 13:18:14 +02:00
cfsmp3
183e613981 Merge branch 'pr/n93_wforums' 2014-08-08 16:39:02 +02:00
wforums
19e2912a71 AVC fps fix
- Will now change current_fps based on AVC data (if present). Should fix
an issue with low fps video that was submitted.
2014-08-07 21:09:45 +02:00
wforums
dc82154a03 AVC fps fix
Changes.txt updated.
2014-08-07 21:09:31 +02:00
cfsmp3
2029dab3bf Merge branch 'pr/n92_anshul1912' 2014-08-05 21:24:08 +02:00
wforums
405d808d0b WTV fix
Fixed WTV
2014-08-04 21:10:17 +02:00
Anshul Maheshwari
783e889634 showing language at channel in DVB transcript 2014-07-31 01:28:19 +05:30
Anshul Maheshwari
a32c8a3b7f dvb output as transcript 2014-07-30 23:00:55 +05:30
Anshul Maheshwari
5618df35c6 Merge branch 'master' of https://github.com/anshul1912/ccextractor 2014-07-30 21:17:44 +05:30
Anshul Maheshwari
c054594383 output of dvb in srt sami smptett format 2014-07-30 21:17:04 +05:30
Anshul Maheshwari
c58f99378f removing redundant snprintf defines 2014-07-30 00:33:47 -07:00
Anshul Maheshwari
45d1dfe425 merging src/cc_encoders_common.c 2014-07-30 11:45:25 +05:30
Anshul Maheshwari
a5dcf9242d dvb_sub_decoder use common encoder interface 2014-07-30 11:40:12 +05:30
cfsmp3
ecc0714f48 Correction to text files 2014-07-29 10:12:22 +02:00
cfsmp3
26410b991d Version pump 2014-07-29 10:06:45 +02:00
cfsmp3
19b1bff7f4 Merge branch 'pr/n91_anshul1912'
Conflicts:
	docs/CHANGES.TXT
2014-07-29 09:28:28 +02:00
Anshul Maheshwari
bc1aff78d7 updated README 2014-07-29 08:16:00 +02:00
Anshul Maheshwari
2df8931d00 updated changes.txt 2014-07-29 08:13:54 +02:00
wforums
b765198d53 Updated for 0.71
-
2014-07-28 22:22:47 +02:00
cfsmp3
22f620400a Merge branch 'pr/n89_anshul1912' 2014-07-28 21:22:29 +02:00
cfsmp3
a68add78d0 Merge branch 'pr/n88_rkuchumov'
Conflicts:
	docs/CHANGES.TXT
2014-07-28 17:56:15 +02:00
Ruslan Kuchumov
14d866e8a2 -stdin parameter 2014-07-28 18:48:07 +00:00
Anshul Maheshwari
335bca4507 uninitialized values used in encoder 2014-07-28 17:48:25 +02:00
Ruslan Kuchumov
f31425e9f0 cygwin support 2014-07-28 13:57:54 +00:00
Anshul Maheshwari
3f54fab5f4 Indentation of file 2014-07-28 11:19:33 +05:30
Anshul Maheshwari
59c62d48b3 handle memory leakage 2014-07-28 10:55:46 +05:30
Ruslan Kuchumov
a926766478 merge conflict 2014-07-27 23:24:19 +00:00
Ruslan Kuchumov
cc233c61f2 changes.txt 2014-07-27 23:23:11 +00:00
cfsmp3
e9fcdf392f Merge branch 'pr/n83_rkuchumov'
Conflicts:
	src/file_functions.c
	src/params.c
2014-07-27 20:29:05 +02:00
Ruslan
c42f039297 fix 2014-07-26 21:17:20 +04:00
Ruslan Kuchumov
8cbaf09b4f moved udp code to networking.c 2014-07-26 21:07:45 +00:00
Ruslan Kuchumov
ee8d5dff66 goddamn windows 2014-07-26 17:56:58 +00:00
Ruslan Kuchumov
ec0873f5a2 windows support 2014-07-26 12:06:17 +00:00
Ruslan Kuchumov
29515bfcd5 some changes to the protocol 2014-07-25 19:58:16 +00:00
Ruslan Kuchumov
c85ebb0c1e usage & no debug 2014-07-25 18:17:46 +00:00
Ruslan Kuchumov
d6e66d5c7f password 2014-07-24 22:47:47 +00:00
Ruslan Kuchumov
f65f2b229a params 2014-07-24 21:14:56 +00:00
Ruslan Kuchumov
5094351469 listening tcp port 2014-07-24 20:19:13 +00:00
Anshul Maheshwari
5d6a770ce8 error checking for socket 2014-07-23 13:34:36 +05:30
Anshul Maheshwari
010d7f9ce4 error checking in fdprintf 2014-07-23 13:14:20 +05:30
Anshul Maheshwari
fb49e680a6 error checking in getfilesize 2014-07-23 13:10:42 +05:30
Anshul Maheshwari
6b98856892 put telexcc debug code inside a macro 2014-07-23 13:08:04 +05:30
Anshul Maheshwari
1a479a7199 looking for writing beyond the memory
increasing memory to 40, though only 38 is required but to make it
multiple of 4 and 8 looking at 32bit and 64 bit system.
2014-07-23 11:58:38 +05:30
Anshul Maheshwari
2894bcd7ff closed cid 26479 getc does not match eof 2014-07-22 15:36:00 +05:30
Anshul Maheshwari
1ae8040bd7 closing configurtion file correctly 2014-07-22 14:08:02 +05:30
Ruslan Kuchumov
57a80084ce bin support 2014-07-21 13:18:20 +00:00
Ruslan Kuchumov
e35b4ea62c small fix 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
3546526177 teletext support 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
12efb6166a constants 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
9beee068ce debug output 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
9efcba5c02 608 support & params 2014-07-21 11:10:02 +00:00
Ruslan Kuchumov
947333ea64 init 2014-07-21 11:08:29 +00:00
Anshul Maheshwari
7e527fc62a memory leakage for 608_smptett 2014-07-21 14:09:02 +05:30
Anshul Maheshwari
9f78c595b3 resource leak in configuration 2014-07-21 13:54:42 +05:30
Anshul Maheshwari
fa03442c85 leakage of file handler 2014-07-21 13:54:33 +05:30
Anshul Maheshwari
e664c035a1 handle memory leakage 2014-07-21 13:54:04 +05:30
Anshul Maheshwari
c522e3b054 error checking fr cur_xds_payload_length 2014-07-21 13:52:41 +05:30
Anshul Maheshwari
b3c037ab21 indentation of param_c 2014-07-21 12:16:16 +05:30
Anshul Maheshwari
097fdb643b corecting boundary of xds_call_letters 2014-07-21 11:41:42 +05:30
Anshul Maheshwari
43094a9897 fix typo while checking boundary 2014-07-21 11:36:20 +05:30
Anshul Maheshwari
aefa623cd4 reverted typo for xds with mprint 2014-07-20 20:07:28 +05:30
Anshul Maheshwari
1be11738eb removed redundant declaration in header file 2014-07-20 20:06:36 +05:30
Anshul Maheshwari
5a09c116f6 correct xdsprint argument 2014-07-20 14:26:42 +05:30
cfsmp3
bb700db08e Merge branch 'pr/n78_anshul1912' 2014-07-20 10:46:38 +02:00
cfsmp3
2e8582b14c Merge branch 'pr/n74_anshul1912'
Conflicts:
	src/608_sami.c
2014-07-20 10:46:21 +02:00
Anshul Maheshwari
8d47dc2f82 corrected size of expression 2014-07-20 13:37:35 +05:30
Anshul Maheshwari
6a3c736195 Added comments, to use function and structure 2014-07-20 08:53:43 +05:30
Anshul Maheshwari
9463999325 added snprintf in utility 2014-07-19 12:27:22 -07:00
Anshul Maheshwari
e50c30eaaa not to write 0 bytes
write have undefined( not mentioned behaviour when 0 bytes written)
write xds data even if start_time is 0
2014-07-19 22:10:50 +05:30
Anshul Maheshwari
45a3e21897 passed as argument cur_xds_packet_class 2014-07-19 18:34:42 +05:30
Anshul Maheshwari
47dbcdff9c write xds data only when option is passed 2014-07-19 18:15:53 +05:30
Anshul Maheshwari
dc164f81e5 improved xds logic 2014-07-19 17:46:16 +05:30
Anshul Maheshwari
bab0ec8b60 removed implicit declaration warning 2014-07-19 16:35:53 +05:30
Anshul Maheshwari
f543e3f4e2 xds extraction in seprate output context 2014-07-19 16:29:28 +05:30
Ruslan Kuchumov
43d4b9abaa typo fix 2014-07-18 21:45:57 +00:00
Ruslan Kuchumov
f5bbb6aef5 output to stdout when -out=null removed 2014-07-18 21:44:47 +00:00
Ruslan Kuchumov
25b666c2ae seg fault fix 2014-07-18 21:43:53 +00:00
Anshul Maheshwari
78087073ac mpg file correction 2014-07-18 11:23:16 +02:00
Anshul Maheshwari
12c2ced497 corrected transcript for mov files 2014-07-17 17:26:14 +02:00
cfsmp3
87954419ba Typo fix 2014-07-16 14:31:41 +02:00
cfsmp3
0add0bc2e9 Detect out-of-band XDS packets and a couple of other bugfixes. 2014-07-16 14:30:59 +02:00
Anshul Maheshwari
7858afb837 Merge branch 'seprate_output_context' of https://github.com/anshul1912/ccextractor into seprate_output_context 2014-07-16 16:07:21 +05:30
Anshul Maheshwari
69c0b2e223 handling end of data correctly 2014-07-16 16:06:29 +05:30
Anshul Maheshwari
855ca48220 not to use g++ 2014-07-16 16:05:55 +05:30
Anshul Maheshwari
02bee86397 correct value for try_to_add_start_credits 2014-07-14 21:28:27 +05:30
Anshul Maheshwari
315d466da8 updated mythtv for encoder 2014-07-14 18:47:54 +05:30
Anshul Maheshwari
d4597e0094 indentation of mythtv 2014-07-14 17:52:06 +05:30
cfsmp3
b8ff3414c0 Fix is packet size, as reporte by Coverity 2014-07-14 14:12:12 +02:00
Anshul Maheshwari
2206cc1f78 adding encoder in rcwt loop 2014-07-14 17:24:20 +05:30
Anshul Maheshwari
00433467be use_"-12"_and_"-out=raw"_tn_both_fields_in_1_file 2014-07-14 17:20:03 +05:30
Anshul Maheshwari
1000e33e7f adding raw data support 2014-07-14 13:37:30 +05:30
Anshul Maheshwari
a64245fb5b correcting help message typo 2014-07-14 13:37:07 +05:30
Anshul Maheshwari
2f784f00ff correcting logic of devide time
Added another loop so that data whose start time is
already set, does not get affected while setting
others time.

in cc_encoder doing data++ so that it can buffer
more then 2 data
2014-07-14 13:32:54 +05:30
Anshul Maheshwari
136012c558 moving write header in init_encoder
RCWT header can't have a BOM before it, or parsing it later will not
be possible
2014-07-13 18:40:50 +05:30
Anshul Maheshwari
874abf6442 added encoder context in spupng 2014-07-13 18:28:39 +05:30
Anshul Maheshwari
20975957ee corrected corruption of sub for mp4 2014-07-13 18:28:33 +05:30
Anshul Maheshwari
1fabae2870 using encoder from cc_encoder_common 2014-07-13 18:28:28 +05:30
Anshul Maheshwari
abb3523ee3 passing encoder context 2014-07-13 18:28:22 +05:30
Anshul Maheshwari
ec63a06e25 generic-code-from-608-encoder-to-common-encoder 2014-07-13 18:28:16 +05:30
Anshul Maheshwari
8b4353f08c passing-subtitle-in-output_c 2014-07-13 18:28:11 +05:30
Anshul Maheshwari
8bfb3b87c3 remove declaration conflicts 2014-07-13 18:28:06 +05:30
Anshul Maheshwari
f1a493b999 passing-subtitle-in-myth.c-n-sequencing.c 2014-07-13 18:28:00 +05:30
Anshul Maheshwari
3afcfa79e1 allocating-cc_subtitle-for-mp4 2014-07-13 18:27:55 +05:30
Anshul Maheshwari
adaa436f6b allocating-cc_subtitle-in-general_loop.c 2014-07-13 18:27:49 +05:30
Anshul Maheshwari
37135762c5 passing-av-subtitle-in-es_userdata.c 2014-07-13 18:27:44 +05:30
Anshul Maheshwari
e6aa7128df passing cc_subtitle in ccextractor_h n es_function_c 2014-07-13 18:27:37 +05:30
Anshul Maheshwari
da8d4a290c passing cc_subtitle in src/avc_functions.c 2014-07-13 18:27:30 +05:30
Anshul Maheshwari
4d11a727d9 passing cc_subtitle in cc608 decoder 2014-07-13 18:27:20 +05:30
Anshul Maheshwari
3c232bfca0 Merge remote-tracking branch 'upstream/master' 2014-07-13 18:24:37 +05:30
Anshul Maheshwari
b3fe96477a dereferebcing NULL pointer 2014-07-13 18:08:44 +05:30
Anshul Maheshwari
5f87544a0d Invalid memory access at boundary 2014-07-13 01:43:27 +05:30
cfsmp3
f0c0ca4566 Merge branch 'pr/n73_anshul1912' 2014-07-12 21:26:45 +02:00
Anshul Maheshwari
23719526cd update changes_text 2014-07-13 00:54:57 +05:30
cfsmp3
67ffe22460 Merge branch 'pr/n72_anshul1912' 2014-07-12 21:18:07 +02:00
Anshul Maheshwari
08996a3253 using freep and removing redundant code 2014-07-12 19:42:38 +05:30
Anshul Maheshwari
95e2f7665b corrected time roll up 2014-07-12 11:28:43 +05:30
Anshul Maheshwari
a5ef2d1574 some memory check before accessing 2014-07-11 13:13:48 -07:00
Anshul Maheshwari
cc0a786004 compile on windows 2014-07-11 22:13:33 +05:30
Anshul Maheshwari
4d6693d948 cleaned mp4.c file 2014-07-11 19:09:34 +05:30
Anshul Maheshwari
9c0792c5a0 using time from data structure 2014-07-11 18:51:04 +05:30
Anshul Maheshwari
0f06f47ab4 logic to devide time between frames 2014-07-11 18:40:00 +05:30
Anshul Maheshwari
5371f854fc indentation of 608_srt.c 2014-07-11 16:59:20 +05:30
wforums
bd49f0f959 Fix for .bin/RCWT file generation
When not using latin1 charset, we were producing unreadable .bin files.

Fixed by adding a separate case where for an RCWT under no circumstance
BOM's can be added before the header.
2014-07-10 12:37:30 +02:00
Willem
63d3071233 Merge pull request #1 from CCExtractor/master
put wtv specific dump in WTV_DEBUG macro
2014-07-10 11:36:00 +02:00
Anshul Maheshwari
015a50bafd put wtv specific dump in WTV_DEBUG macro 2014-07-07 18:02:59 +05:30
Anshul Maheshwari
1ee4b9bd01 put wtv specific dump in WTV_DEBUG macro 2014-07-07 17:45:12 +05:30
131 changed files with 16026 additions and 8905 deletions

View File

@@ -4,7 +4,7 @@ MAINTAINER = Marc Espie <espie@openbsd.org>
CATEGORIES = multimedia
COMMENT = closed caption subtitles extractor
HOMEPAGE = http://ccextractor.sourceforge.net/
V = 0.70
V = 0.75
DISTFILES = ccextractor.${V:S/.//}-src.zip
MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=ccextractor/}
DISTNAME = ccextractor-$V

View File

@@ -1,21 +1,12 @@
ccextractor
===========
CCExtractor - Carlos' version (mainstream).
Carlos' version (mainstream) is the most stable branch.
0.70 - GSOC
-----------
This is the first release that is part of Google's Summer of Code.
Anshul, Ruslan and Willem joined CCExtractor to work on a number of things
over the summer, and their work is already reaching the mainstream
version of CCExtractor.
Extracting subtitles has never been so easy. Just type the following command:
ccextrator "name of input"
- Added a huge dictionary submitted by Matt Stockard.
- Added DVB subtitles decoder, spupng in output
- Added support for cdt2 media atoms in QT video files. Now multiple atoms in
a single sample sequence are supported.
- Changed Makefile.
- Fixed some bugs.
- Added feature to print info about file's subtitles and streams.
- Support Long PMT.
- Support Configuration file.
Gui lovers should download the Sorceforge version of CCExtractor, the Git Version is not your cup of tea.
http://ccextractor.sourceforge.net/download-ccextractor.html
For News about release, please find CHANGES.TXT

View File

@@ -1,5 +1,52 @@
0.70 - GSOC
-----------
0.76 (2015-03-28)
-----------------
- Added basic M2TS support
- Added EPG support - you can now export the Program Guide to XML
- Some bugfixes
0.75 (2015-01-15)
-----------------
- Fixed issue with teletext to other then srt.
- CCExtractor can be used as library if compiled using cmake
- By default the Windows version adds BOM to generated UTF files (this is
because it's needed to open the files correctly) while all other
builds don't add it (because it messes with text processing tools).
You can use -bom and -nobom to change the behaviour.
0.74 (2014-09-24)
-----------------
- Fixed issue with -o1 -o2 and -12 parameters (where it would write output only in the o2 file)
- Fixed UCLA parameter issue. Now the UCLA parameter settings can't be overwritten anymore by later parameters that affect the custom transcript
- Switched order around for TLT and TT page number in custom transcript to match UCLA settings
- Added nobom parameter, for when files are processed by tools that can't handle the BOM. If using this, files might be not readable under windows.
- Segfault fix when no input files were given
- No more bin output when sending to server + possibility to send TT to server for processing
- Windows: Added the Microsoft redistributable MSVCR120.DLL to both the installation package and the application zip.
0.73 - GSOC (2014-08-19)
------------------------
- Added support of BIN format for Teletext
- Added start of librarisation. This will allow in the future for other programs to use encoder/decoder functions and more.
0.72 - GSOC (2014-08-12)
------------------------
- Fix for WTV files with incorrect timing
- Added support for fps change using data from AVC video track in a H264 TS file.
- Added FFMpeg Support to enable all encapsulator and decoder provided by ffmpeg
0.71 - GSOC (2014-07-31)
------------------------
- Added feature to receive captions in BIN format according to CCExtractor's own
protocol over TCP (-tcp port [-tcppassword password])
- Added ability to send captions to the server described above or to the
online repository (-sendto host[:port])
- Added -stdin parameter for reading input stream from standard input
- Compilation in Cygwin using linux/Makefile
- Fix for .bin files when not using latin1 charset
- Correction of mp4 timing, when one timestamp points timing of two atom
0.70 - GSOC (2014-07-06)
------------------------
This is the first release that is part of Google's Summer of Code.
Anshul, Ruslan and Willem joined CCExtractor to work on a number of things
over the summer, and their work is already reaching the mainstream
@@ -37,9 +84,10 @@ version of CCExtractor.
1111001 is the default setting for -ucla
Make sure you use this parameter after others that might affect these
settings (-out, -ucla, -xds, -txt, -ttxt, ...)
- Fixed Negative timing Bug
0.69
----
0.69 (2014-04-05)
-----------------
- A few patches from Christopher Small, including proper support
for multiple multicast clients listening on the same port.
- GUI: Fixed teletext preview.
@@ -58,8 +106,8 @@ version of CCExtractor.
- Windows GUI: Some code refactoring, since the HDHomeRun support makes
the code larger enough to require more than one source file :-)
0.68
----
0.68 (2013-12-24)
-----------------
- A couple of shared variables between 608 decoders were causing
problems when both fields were processed at the same time with
-12, fixed.
@@ -73,8 +121,8 @@ version of CCExtractor.
(Heleen Buus).
- Some fixes (Chris Small).
0.67
----
0.67 (2013-10-09)
-----------------
- Padding bytes were being discarded early in the process in 0.66,
which is convenient for debugging, but it messes with timing in
.raw, which depends on padding. Fixed.
@@ -94,8 +142,8 @@ version of CCExtractor.
roll-up mode.
0.66
----
0.66 (2013-07-01)
-----------------
- Fixed bug in auto detection code that triggered a message
about file being auto of sync.
- Added -investigate_packets
@@ -173,8 +221,8 @@ version of CCExtractor.
- Added -noautotimeref: Prevent UTC reference from being auto set from
the stream data.
0.65
----
0.65 (2013-03-14)
-----------------
- Minor GUI changes for teletext
- Added end timestamps in timed transcripts
- Added support for SMPTE (patch by John Kemp)
@@ -192,8 +240,8 @@ version of CCExtractor.
display their contents (-parsePAT and -parsePMT) which makes
troubleshooting easier.
0.64
----
0.64 (2012-10-29)
-----------------
- Changed Window GUI size (larger).
- Added Teletext options to GUI.
- Added -teletext to force teletext mode even if not detected
@@ -213,8 +261,8 @@ version of CCExtractor.
- Added --nogoptime to force PTS timing even when CCExtractor would
use GOP timing otherwise.
0.63
----
0.63 (2012-08-17)
-----------------
- Telext support added, by integrating Petr Kutalek's telxcc. Integration is
still quite basic (there's equivalent code from both CCExtractor and
telxcc) and some clean up is needed, but it works. Petr has announced that
@@ -222,8 +270,8 @@ version of CCExtractor.
CCExtractor.
- Some bug fixes, as usual.
0.62
----
0.62 (2012-05-23)
-----------------
- Corrected Mac build "script" (needed to add GPAC includes). Thanks to the
Mac users that sent this.
- Hauppauge mode now uses PES timing, needed for files that don't have
@@ -245,8 +293,8 @@ version of CCExtractor.
or certain samples (we had none like this in our test collection). Thanks,
Rajesh.
0.61
----
0.61 (2012-03-08)
-----------------
- Fix: GCC 3.4.4 can now build CCExtractor.
- Fix: Damaged TS packets (those that come with 'error in transport' bit
on) are now skipped.
@@ -256,8 +304,8 @@ version of CCExtractor.
anything but please report).
- Some non-interesting cleanup.
0.60
----
0.60 (unreleased)
-----------------
- Add: MP4 support, using GPAC (a media library). Integration is currently
"enough so it works", but needs some more work. There's some duplicate
code, the stream must be a file (no streaming), etc.
@@ -267,8 +315,8 @@ version of CCExtractor.
roll-up) was broken, with complete lines being missing.
- Fix: bin format not working as input.
0.59
----
0.59 (2011-10-07)
-----------------
- More AVC/H.264 work. pic_order_cnt_type != 0 will be processed now.
- Fix: Roll-up captions with interruptions for Text (with ResumeTextDisplay
in the middle of the caption data) were missing complete lines.
@@ -296,8 +344,8 @@ version of CCExtractor.
- Some code clean up, minor refactoring.
- Teletext detection (not yet processing).
0.58
----
0.58 (2011-08-21)
-----------------
- Implemented new PTS based mode to order the caption information
of AVC/H.264 data streams. The old pic_order_cnt_lsb based method
is still available via the -poc or --usepicorder command switches.
@@ -321,18 +369,18 @@ version of CCExtractor.
output are processed OK.
- Updated Windows GUI.
0.57
----
0.57 (2010-12-16)
-----------------
- Bugfixes in the Windows version. Some debug code was unintentionally
left in the released version.
0.56
----
0.56 (2010-12-09)
-----------------
- H264 support
- Other minor changes a lot less important
0.55
----
0.55 (2009-08-09)
-----------------
- Replace pattern matching code with improved parser for MPEG-2 elementary
streams.
- Fix parsing of ReplayTV 5000 captions.
@@ -347,8 +395,8 @@ version of CCExtractor.
because of the odd number of fields. I used top_field_first to tell when the channels
are reversed. See Table 6-1 of the SCTE 20 [Paul Fernquist]
0.54
----
0.54 (2009-04-16)
-----------------
- Add -nosync and -fullbin switches for debugging purposes.
- Remove -lg (--largegops) switch.
- Improve syncronization of captions for source files with
@@ -361,8 +409,8 @@ version of CCExtractor.
- Added a feature to add start and end messages (for credits).
See help screen for details.
0.53
----
0.53 (2009-02-24)
-----------------
- Force generated RCWT files to have the same length as source file.
- Fix documentation for -startat / -endat switches.
- Make -startat / -endat work with all output formats.
@@ -388,8 +436,8 @@ version of CCExtractor.
it (there's not .NET 3.5 for Windows 2000), as
requested by a couple of key users.
0.51
----
0.51 (unreleased)
-----------------
- Removed -autopad and -goppad, no longer needed.
- In preparation to a new binary format we have
renamed the current .bin to .raw. Raw files
@@ -414,14 +462,14 @@ version of CCExtractor.
too.
- [Volker] Dish Network clean-up
0.50
----
0.50 (2008-12-12)
-----------------
- [Volker] Fix in DVR-MS NTSC timing
- [Volker] More clean-up
- Minor fixes
0.49
----
0.49 (2008-12-10)
-----------------
- [Volker] Major MPEG parser rework. Code much
cleaner now.
- Some stations transmit broken roll-up captions,
@@ -438,8 +486,8 @@ version of CCExtractor.
- [Volker] Added support for DVR-MS NTSC files.
- Other minor bugfixes and changes.
0.46
----
0.46 (2008-11-24)
-----------------
- Added support for live streaming, ccextractor
can now process files that are being recorded
at the same time.
@@ -452,9 +500,8 @@ version of CCExtractor.
Note: For now, it's only ATSC recordings, not
NTSC (analog) recordings.
0.45
----
0.45 (2008-11-14)
-----------------
- Added autodetection of DVR-MS files.
- Added -asf to force DVR-MS mode.
- Added some specific support for DVR-MS
@@ -474,8 +521,8 @@ version of CCExtractor.
need ccextractor to use GOP timing in large
GOPs.
0.44
----
0.44 (2008-09-10)
-----------------
- Added an option to the GUI to process
individual files in batch, i.e. call
ccextractor once per file. Use it if you
@@ -486,8 +533,8 @@ version of CCExtractor.
- Several minor bugfixes.
- Updated the GUI to add the new options.
0.43
----
0.43 (2008-06-20)
-----------------
- Fixed a bug in the read loop (no less)
that caused some files to fail when
reading without buffering (which is
@@ -495,16 +542,16 @@ version of CCExtractor.
- Several improvements in the GUI, such as
saving current options as default.
0.42
----
0.42 (2008-06-17)
-----------------
- The option switch "-transcript" has been
changed to "--transcript". Also, "-txt"
has been added as the short alias.
- Windows GUI
- Updated help screen
0.41
----
0.41 (2008-06-15)
-----------------
- Default output is now .srt instead of .bin,
use -raw if you need the data dump instead of
.srt.
@@ -516,15 +563,15 @@ version of CCExtractor.
there aren't useless. But if they annoy
you go ahead...
0.40
----
0.40 (2008-05-20)
-----------------
- Fixed a bug in the sanity check function
that caused the Myth branch to abort.
- Fixed the OSX build script, it needed a
new #define to work.
0.39
----
0.39 (2008-05-11)
-----------------
- Added a -transcript. If used, the output will
have no time information. Also, if in roll-up
mode there will be no repeated lines.
@@ -557,8 +604,8 @@ version of CCExtractor.
join the subs), use -ve.
0.36
----
0.36 (unreleased)
-----------------
- Fixed bug in SMI, nbsp was missing a ;.
- Footer for SAMI files was incorrect (<body> and
<sami> tags were being opened again instead of
@@ -588,8 +635,8 @@ version of CCExtractor.
as usual.
0.35
----
0.35 (unreleased)
-----------------
- Added --defaultcolor to the help screen. Code
was already in 0.34 but the documentation wasn't
updated.
@@ -598,8 +645,8 @@ version of CCExtractor.
- At the end of the process, a ratio between
video length and time to process is displayed.
0.34
----
0.34 (2007-06-03)
-----------------
- Added some basic letter case and capitalization
support. For captions that broadcast in ALL
UPPERCASE (most of them), ccextractor can now
@@ -650,8 +697,8 @@ version of CCExtractor.
Number (0.0.0.34 in this version) in case
you want to check for version info.
0.33
----
0.33 (unreleased)
-----------------
- Added -scr or --screenfuls, to select the
number of screenfuls ccextractor should
write before exiting. A screenful is
@@ -670,8 +717,8 @@ version of CCExtractor.
Use -nofc or --nofontcolor if you don't
want these tags.
0.32
----
0.32 (unreleased)
-----------------
- Added -delay ms, which adds (or substracts)
a number of milliseconds to all times in
.srt/.sami files. For example,
@@ -690,8 +737,8 @@ version of CCExtractor.
such as from minute 3 to minute 5. Check
help screen for exact syntax.
0.31
----
0.31 (unreleased)
-----------------
- Added -dru (direct rollup), which causes
roll-up captions to be written as
they would on TV instead of line by line.
@@ -699,20 +746,20 @@ version of CCExtractor.
and ugly too (each line is written many
times, two characters at time).
0.30
----
0.30 (2007-05-24)
-----------------
- Fix in extended char decoding, I wasn't
replacing the previous char.
- When a sequence code was found before
having a PTS, reported time was
undefined.
0.29
----
0.29 (unreleased)
-----------------
- Minor bugfix.
0.28
----
0.28 (unreleased)
-----------------
- Fixed a buffering related issue. Short version,
the first 2 Mb in non-TS mode were being
discarded.
@@ -721,20 +768,20 @@ version of CCExtractor.
they are not part of the .srt "standard"
even if McPoodle add them.
0.27
----
0.27 (unreleased)
-----------------
- Modified sanitizing code, it's less aggresive
now. Ideally it should mean that characters
won't be missed anymore. We'll see.
0.26
----
0.26 (unreleased)
-----------------
- Added -gp (or -goppad) to make ccextractor use
GOP timing. Try it for non TS files where
subs start OK but desync as the video advances.
0.25
----
0.25 (unreleased)
-----------------
- Format detection is not perfect yet. I've added
-nomyth to prevent the MytvTV code path to be
called. I've seen apparently correct files that
@@ -744,8 +791,8 @@ version of CCExtractor.
options will work.
0.24
----
0.24 (unreleased)
-----------------
- Fixed a bug that caused dvr-ms (Windows Media Center)
files to be incorrectly processed (letters out of
order all the time).
@@ -759,8 +806,8 @@ version of CCExtractor.
still can).
0.22
----
0.22 (2007-05-15)
-----------------
- Added text mode handling into decoder, which gets rids
of junk when text mode data is present.
- Added support for certain (possibly non standard
@@ -771,8 +818,8 @@ version of CCExtractor.
- Other Minor bug fixes.
0.20
----
0.20 (2007-05-07)
-----------------
- Unicode should be decent now.
- Added support for Hauppauge PVR 250 cards, and (possibly)
many others (bttv) with the same closed caption recording
@@ -789,8 +836,8 @@ version of CCExtractor.
though. If you have a good CSS for .SAMI files let me
know.
0.19
----
0.19 (2007-05-03)
-----------------
- Work on Dish Network streams, timing was completely broken.
It's fixed now at least for the samples I have, if it's not
completely fixed let me know. Credit for this goes to
@@ -801,8 +848,8 @@ version of CCExtractor.
- Added Unicode and Latin-1 encoding.
0.17
----
0.17 (2007-04-29)
-----------------
- Extraction to .srt is almost complete - works correctly for
pop-up and roll-up captions, possibly not yet for paint-on
(mostly because I don't have any sample with paint-on captions
@@ -810,8 +857,8 @@ version of CCExtractor.
- Minor bug fixes.
- Automatic TS/non-TS mode detection.
0.14
----
0.14 (2007-04-25)
-----------------
- Work on handling special cases related to the MPEG reference
clock: Roll over, jumps, etc.
- Modified padding code a bit: In particular, padding occurs
@@ -824,8 +871,8 @@ version of CCExtractor.
needs to start with a TS header).
- Minor bug fixes.
0.07
----
0.07 (2007-04-19)
-----------------
- Added MPEG reference clock parsing.
- Added autopadding in TS. Does miracles with timing.
- Added video information (as extracted from sequence header).

58
docs/FFMPEG.TXT Normal file
View File

@@ -0,0 +1,58 @@
Overview
========
FFmpeg Intigration was done to support multiple encapsulator.
Dependecy
=========
FFmpeg library's
Download and Install FFmpeg on your linux pc.
---------------------------------------------
Download latest source code from following link
https://ffmpeg.org/download.html
then following command to install ffmpeg
./configure && make && make install
Note:If you installed ffmpeg on non standurd location, please change/update your
enviorment variable $PATH and $LD_LIBRARY_PATH
Download and Install FFmpeg on your Windows pc.
----------------------------------------------
Download prebuild library from following link
http://ffmpeg.zeranoe.com/builds/
You need to download Shared Versions to run the program and Dev Versions to compile.
How to compile ccextractor
==========================
In Linux
--------
make ENABLE_FFMPEG=yes
On Windows
----------
put the path of libs/include of ffmpeg library in library paths.
step 1) In visual studio 2013 right click <Project> and select property.
step 2) Select Configuration properties in left panel(column) of property.
step 3) Select VC++ Directory.
step 4) In the right pane, in the right-hand column of the VC++ Directory property,
open the drop-down menu and choose Edit.
Step 5) Add path of Directory where you have kept uncompressed library of FFmpeg.
Set preprocessor flag ENABLE_FFMPEG=1
Step 1)In visual studio 2013 right click <Project> and select property.
Step 2)In the left panel, select Configuration Properties, C/C++, Preprocessor.
Step 3)In the right panel, in the right-hand column of the Preprocessor Definitions property, open the drop-down menu and choose Edit.
Step 4)In the Preprocessor Definitions dialog box, add ENABLE_FFMPEG=1. Choose OK to save your changes.
Add library in linker
step 1)Open property of project
Step 2)Select Configuration properties
Step 3)Select Linker in left panel(column)
Step 4)Select Input
Step 5)Select Additional dependencies in right panel
Step 6)Add all FFmpeg's lib in new line

View File

@@ -6,8 +6,8 @@ extract text from images. In the World of Subtile, subtitle stored
in bitmap format are common and even neccassary. for converting subtile
in bitmap format to subtilte in text format ocr is used.
Dependecy
=========
Dependency
==========
Tesseract (OCR library by google)
Leptonica (image processing library)
@@ -55,7 +55,7 @@ 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
@@ -90,7 +90,7 @@ Step 7)Add liblept168.lib in new line
Download language data from following link
https://code.google.com/p/tesseract-ocr/downloads/list
after downloading the tesseract-ocr-3.02.eng.tar extract the tar file and put
after downloading the tesseract-ocr-3.02.eng.tar.gz extract the tar file and put
tessdata folder where you have kept ccextractor executable
Copy the tesseract and leptonica dll in the folder of executable or in system32.

View File

@@ -1,4 +1,4 @@
ccextractor, 0.63
ccextractor, 0.75
-----------------
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
Maintainer: cfsmp3
@@ -7,12 +7,17 @@ Lots of credit goes to other people, though:
McPoodle (author of the original SCC_RIP), Neuron2, and others (see source
code).
Home: http://ccextractor.sourceforge.net
Home: http://www.ccextractor.org
You can subscribe to new releases notifications at freshmeat:
http://freshmeat.net/projects/ccextractor
Google Summer of Code 2014 students
- Willem van iseghem
- Ruslan KuchumoV
- Anshul Maheshwari
License
-------
GPL 2.0.
@@ -67,21 +72,18 @@ If there are Spanish subtitles, one of them should work.
McPoodle's page
---------------
http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_TOOLS.HTML
http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_TOOLS.HTML
Essential CC related information and free (with source) tools.
Encoding
--------
This version, in both its Linux and Windows builds generates by
default Latin-1 encoded files. You can use -unicode and -utf8
if you prefer these encodings (usually it just depends on what
your specific player likes).
This has changed from the previous UTF-8 default which vobsub
can't handle.
default Unicode files. You can use -latin1 and -utf8 if you prefer
these encodings (usually it just depends on what your specific
player likes).
Future work
-----------
- Finish EIA-708 decoder
- Network support
- Please check www.ccextractor.org for news and future work.

View File

@@ -0,0 +1,28 @@
For building ccextractor using cmake folllow below steps..
Step 1) Check you have right version of cmake installed. ( version >= 3.0.2 )
We are using CMP0037 policy of cmake which was introduced in 3.0.0
since we have tested our system only with cmake version 3.0.2, I would
suggest to use 3.0.2 or higher version.
Step 2) create a seprate directory where you want to build the target.
In Unix you can do it using follwing commands.
~> cd ccextractor
~> mkdir build
Step 3) make the build sytem using cmake
~> cmake ../src/
Step 4) Compile the code.
~> make
~> make install
Step 5) Use CCextractor as you would like
If you want to build CCExtractor with FFMpeg you need to pass
cmake -DWITH_FFMPEG=ON ../src/
Hint for looking all the things you want to set from outside
cmake -LAH ../src/

View File

@@ -1,22 +1,28 @@
SHELL = /bin/sh
CC = gcc
CXX = g++
SYS := $(shell gcc -dumpmachine)
CFLAGS = -O3 -std=gnu99
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib
ALL_FLAGS = -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64
LDFLAGS = -lm -zmuldefs
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib -I../src/lib_ccx -I../src/.
ALL_FLAGS = -Wno-write-strings -D_FILE_OFFSET_BITS=64
LDFLAGS = -lm
ifneq (, $(findstring linux, $(SYS)))
CFLAGS +=-DGPAC_CONFIG_LINUX
endif
TARGET = ccextractor
OBJS_DIR = objs
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib:../src/lib_ccx
SRCS_DIR = ../src
SRCS_C = $(wildcard $(SRCS_DIR)/*.c)
OBJS = $(SRCS_C:$(SRCS_DIR)/%.c=$(OBJS_DIR)/%.o)
SRCS_CCX_DIR = $(SRCS_DIR)/lib_ccx
SRCS_CCX = $(wildcard $(SRCS_CCX_DIR)/*.c)
OBJS_CCX = $(SRCS_CCX:$(SRCS_CCX_DIR)/%.c=$(OBJS_DIR)/%.o)
SRCS_PNG_DIR = $(SRCS_DIR)/libpng
SRCS_PNG = $(wildcard $(SRCS_PNG_DIR)/*.c)
OBJS_PNG = $(SRCS_PNG:$(SRCS_PNG_DIR)/%.c=$(OBJS_DIR)/%.o)
@@ -36,9 +42,39 @@ INSTLALL_PROGRAM = $(INSTLALL)
DESTDIR = /usr/bin
ifeq ($(ENABLE_OCR),yes)
CFLAGS+=-I/usr/local/include/tesseract -I/usr/local/include/leptonica
CFLAGS+=-DENABLE_OCR
LDFLAGS+= $(shell pkg-config --libs tesseract)
TESS_LDFLAGS+= $(shell pkg-config --libs tesseract)
LEPT_LDFLAGS+= $(shell pkg-config --libs lept)
#error checking of library are there or not
ifeq ($(TESS_LDFLAGS),$(EMPTY))
$(error **ERROR** "tesseract not found")
else
#TODO print the version of library found
$(info "tesseract found")
endif
ifeq ($(LEPT_LDFLAGS),$(EMPTY))
$(error **ERROR** "leptonica not found")
else
#TODO print the version of library found
$(info "Leptonica found")
endif
CFLAGS += $(shell pkg-config --cflags tesseract)
CFLAGS += $(shell pkg-config --cflags lept)
LDFLAGS += $(TESS_LDFLAGS)
LDFLAGS += $(LEPT_LDFLAGS)
endif
ifeq ($(ENABLE_FFMPEG),yes)
CFLAGS+=-DENABLE_FFMPEG
CFLAGS+= $(shell pkg-config --cflags libavcodec)
CFLAGS+= $(shell pkg-config --cflags libavformat)
CFLAGS+= $(shell pkg-config --cflags libavutil)
LDFLAGS+= $(shell pkg-config --libs libavcodec )
LDFLAGS+= $(shell pkg-config --libs libavformat )
LDFLAGS+= $(shell pkg-config --libs libavutil )
endif
.PHONY: all
@@ -48,8 +84,8 @@ all: objs_dir $(TARGET)
objs_dir:
mkdir -p $(OBJS_DIR)
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB)
$(CXX) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(OBJS_CCX)
$(CC) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_CCX) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
$(OBJS_DIR)/%.o: %.c
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@
@@ -60,7 +96,7 @@ $(OBJS_DIR)/%.o: %.cpp
.PHONY: clean
clean:
rm $(TARGET) 2>/dev/null || true
rm $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
rm $(OBJS_CCX) $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
rm -rd $(OBJS_DIR) 2>/dev/null || true
rm .depend 2>/dev/null || true
@@ -74,7 +110,7 @@ uninstall:
.PHONY: depend dep
depend dep:
$(CXX) $(CXXFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) \
$(CC) $(CFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) $(SRCS_CXX) \
$(SRCS_GPACMP4_C) $(SRCS_GPACMP4_CPP) |\
sed 's/^[a-zA-Z_0-9]*.o/$(OBJS_DIR)\/&/' > .depend

View File

@@ -1,2 +1,2 @@
#!/bin/bash
gcc -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64 -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
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

2
mac/build.command Normal file → Executable file
View File

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

151
src/608.h
View File

@@ -1,151 +0,0 @@
#ifndef __608_H__
enum cc_modes
{
MODE_POPON = 0,
MODE_ROLLUP_2 = 1,
MODE_ROLLUP_3 = 2,
MODE_ROLLUP_4 = 3,
MODE_TEXT = 4,
MODE_PAINTON = 5,
// Fake modes to emulate stuff
MODE_FAKE_ROLLUP_1 = 100
};
struct eia608_screen // A CC buffer
{
unsigned char characters[15][33];
unsigned char colors[15][33];
unsigned char fonts[15][33]; // Extra char at the end for a 0
int row_used[15]; // Any data in row?
int empty; // Buffer completely empty?
};
struct s_context_cc608
{
struct eia608_screen buffer1;
struct eia608_screen buffer2;
int cursor_row, cursor_column;
int visible_buffer;
int srt_counter; // Number of subs currently written
int screenfuls_counter; // Number of meaningful screenfuls written
LLONG current_visible_start_ms; // At what time did the current visible buffer became so?
// unsigned current_visible_start_cc; // At what time did the current visible buffer became so?
enum cc_modes mode;
unsigned char last_c1, last_c2;
int channel; // Currently selected channel
unsigned char color; // Color we are currently using to write
unsigned char font; // Font we are currently using to write
int rollup_base_row;
LLONG ts_start_of_current_line; /* Time at which the first character for current line was received, =-1 no character received yet */
LLONG ts_last_char_received; /* Time at which the last written character was received, =-1 no character received yet */
int new_channel; // The new channel after a channel change
int my_field; // Used for sanity checks
long bytes_processed_608; // To be written ONLY by process_608
struct ccx_s_write *out;
int have_cursor_position;
};
extern unsigned char *enc_buffer;
extern unsigned char str[2048];
extern unsigned enc_buffer_used;
extern unsigned enc_buffer_capacity;
extern int new_sentence;
extern const char *color_text[][2];
int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *context);
void write_stringz_as_srt(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data);
void capitalize (int line_num, struct eia608_screen *data);
void correct_case (int line_num, struct eia608_screen *data);
int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *context);
void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc608 *context);
void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end);
void correct_case (int line_num, struct eia608_screen *data);
void capitalize (int line_num, struct eia608_screen *data);
void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank);
unsigned get_decoder_line_basic (unsigned char *buffer, int line_num, struct eia608_screen *data);
unsigned get_decoder_line_encoded_for_gui (unsigned char *buffer, int line_num, struct eia608_screen *data);
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data);
void delete_all_lines_but_current (struct eia608_screen *data, int row);
void try_to_add_start_credits(struct s_context_cc608 *context);
void try_to_add_end_credits(struct s_context_cc608 *context);
void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *context);
void handle_end_of_data(struct s_context_cc608 *context);
void process608(const unsigned char *data, int length, struct s_context_cc608 *context);
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c);
void get_char_in_unicode (unsigned char *buffer, unsigned char c);
int get_char_in_utf_8 (unsigned char *buffer, unsigned char c);
unsigned char cctolower (unsigned char c);
unsigned char cctoupper (unsigned char c);
int general_608_init (void);
LLONG get_visible_end (void);
#define CC608_SCREEN_WIDTH 32
#define REQUEST_BUFFER_CAPACITY(length) if (length>enc_buffer_capacity) \
{enc_buffer_capacity=length*2; enc_buffer=(unsigned char*) realloc (enc_buffer, enc_buffer_capacity); \
if (enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
}
enum color_code
{
COL_WHITE = 0,
COL_GREEN = 1,
COL_BLUE = 2,
COL_CYAN = 3,
COL_RED = 4,
COL_YELLOW = 5,
COL_MAGENTA = 6,
COL_USERDEFINED = 7,
COL_BLACK = 8,
COL_TRANSPARENT = 9
};
enum font_bits
{
FONT_REGULAR = 0,
FONT_ITALICS = 1,
FONT_UNDERLINED = 2,
FONT_UNDERLINED_ITALICS = 3
};
enum command_code
{
COM_UNKNOWN = 0,
COM_ERASEDISPLAYEDMEMORY = 1,
COM_RESUMECAPTIONLOADING = 2,
COM_ENDOFCAPTION = 3,
COM_TABOFFSET1 = 4,
COM_TABOFFSET2 = 5,
COM_TABOFFSET3 = 6,
COM_ROLLUP2 = 7,
COM_ROLLUP3 = 8,
COM_ROLLUP4 = 9,
COM_CARRIAGERETURN = 10,
COM_ERASENONDISPLAYEDMEMORY = 11,
COM_BACKSPACE = 12,
COM_RESUMETEXTDISPLAY = 13,
COM_ALARMOFF =14,
COM_ALARMON = 15,
COM_DELETETOENDOFROW = 16,
COM_RESUMEDIRECTCAPTIONING = 17,
// Non existing commands we insert to have the decoder
// special stuff for us.
COM_FAKE_RULLUP1 = 18
};
#define __608_H__
#endif

View File

@@ -1,438 +0,0 @@
#include "ccextractor.h"
#include "utility.h"
//extern unsigned char encoded_crlf[16];
// Encodes a generic string. Note that since we use the encoders for closed caption
// data, text would have to be encoded as CCs... so using special characters here
// it's a bad idea.
unsigned encode_line (unsigned char *buffer, unsigned char *text)
{
unsigned bytes=0;
while (*text)
{
switch (ccx_options.encoding)
{
case CCX_ENC_UTF_8:
case CCX_ENC_LATIN_1:
*buffer=*text;
bytes++;
buffer++;
break;
case CCX_ENC_UNICODE:
*buffer=*text;
*(buffer+1)=0;
bytes+=2;
buffer+=2;
break;
}
text++;
}
return bytes;
}
void correct_case(int line_num,struct eia608_screen *data)
{
char delim[64] = {
' ' ,'\n','\r', 0x89,0x99,
'!' , '"', '#', '%' , '&',
'\'', '(', ')', ';' , '<',
'=' , '>', '?', '[' ,'\\',
']' , '*', '+', ',' , '-',
'.' , '/', ':', '^' , '_',
'{' , '|', '}', '~' ,'\0' };
char *line = strdup(((char*)data->characters[line_num]));
char *oline = (char*)data->characters[line_num];
char *c = strtok(line,delim);
do
{
char **index = bsearch(&c,spell_lower,spell_words,sizeof(*spell_lower),string_cmp);
if(index)
{
char *correct_c = *(spell_correct + (index - spell_lower));
size_t len=strlen (correct_c);
memcpy(oline + (c - line),correct_c,len);
}
} while ( ( c = strtok(NULL,delim) ) != NULL );
free(line);
}
void capitalize (int line_num, struct eia608_screen *data)
{
for (int i=0;i<CC608_SCREEN_WIDTH;i++)
{
switch (data->characters[line_num][i])
{
case ' ':
case 0x89: // This is a transparent space
case '-':
break;
case '.': // Fallthrough
case '?': // Fallthrough
case '!':
case ':':
new_sentence=1;
break;
default:
if (new_sentence)
data->characters[line_num][i]=cctoupper (data->characters[line_num][i]);
else
data->characters[line_num][i]=cctolower (data->characters[line_num][i]);
new_sentence=0;
break;
}
}
}
void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank)
{
*last_non_blank=-1;
*first_non_blank=-1;
for (int i=0;i<CC608_SCREEN_WIDTH;i++)
{
unsigned char c=line[i];
if (c!=' ' && c!=0x89)
{
if (*first_non_blank==-1)
*first_non_blank=i;
*last_non_blank=i;
}
}
}
unsigned get_decoder_line_basic (unsigned char *buffer, int line_num, struct eia608_screen *data)
{
unsigned char *line = data->characters[line_num];
int last_non_blank=-1;
int first_non_blank=-1;
unsigned char *orig=buffer; // Keep for debugging
find_limit_characters (line, &first_non_blank, &last_non_blank);
if (!ccx_options.trim_subs)
first_non_blank=0;
if (first_non_blank==-1)
{
*buffer=0;
return 0;
}
int bytes=0;
for (int i=first_non_blank;i<=last_non_blank;i++)
{
char c=line[i];
switch (ccx_options.encoding)
{
case CCX_ENC_UTF_8:
bytes=get_char_in_utf_8 (buffer,c);
break;
case CCX_ENC_LATIN_1:
get_char_in_latin_1 (buffer,c);
bytes=1;
break;
case CCX_ENC_UNICODE:
get_char_in_unicode (buffer,c);
bytes=2;
break;
}
buffer+=bytes;
}
*buffer=0;
return (unsigned) (buffer-orig); // Return length
}
unsigned get_decoder_line_encoded_for_gui (unsigned char *buffer, int line_num, struct eia608_screen *data)
{
unsigned char *line = data->characters[line_num];
unsigned char *orig=buffer; // Keep for debugging
int first=0, last=31;
find_limit_characters(line,&first,&last);
for (int i=first;i<=last;i++)
{
get_char_in_latin_1 (buffer,line[i]);
buffer++;
}
*buffer=0;
return (unsigned) (buffer-orig); // Return length
}
unsigned char *close_tag (unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
{
for (int l=strlen (tagstack)-1; l>=0;l--)
{
char cur=tagstack[l];
switch (cur)
{
case 'F':
buffer+= encode_line (buffer,(unsigned char *) "</font>");
(*pchanged_font)--;
break;
case 'U':
buffer+=encode_line (buffer, (unsigned char *) "</u>");
(*punderlined)--;
break;
case 'I':
buffer+=encode_line (buffer, (unsigned char *) "</i>");
(*pitalics)--;
break;
}
tagstack[l]=0; // Remove from stack
if (cur==tagtype) // We closed up to the required tag, done
return buffer;
}
if (tagtype!='A') // All
fatal (EXIT_BUG_BUG, "Mismatched tags in encoding, this is a bug, please report");
return buffer;
}
unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data)
{
int col = COL_WHITE;
int underlined = 0;
int italics = 0;
int changed_font=0;
char tagstack[128]=""; // Keep track of opening/closing tags
unsigned char *line = data->characters[line_num];
unsigned char *orig=buffer; // Keep for debugging
int first=0, last=31;
if (ccx_options.trim_subs)
find_limit_characters(line,&first,&last);
for (int i=first;i<=last;i++)
{
// Handle color
int its_col = data->colors[line_num][i];
if (its_col != col && !ccx_options.nofontcolor &&
!(col==COL_USERDEFINED && its_col==COL_WHITE)) // Don't replace user defined with white
{
if (changed_font)
buffer = close_tag(buffer,tagstack,'F',&underlined,&italics,&changed_font);
// Add new font tag
buffer+=encode_line (buffer, (unsigned char*) color_text[its_col][1]);
if (its_col==COL_USERDEFINED)
{
// The previous sentence doesn't copy the whole
// <font> tag, just up to the quote before the color
buffer+=encode_line (buffer, (unsigned char*) usercolor_rgb);
buffer+=encode_line (buffer, (unsigned char*) "\">");
}
if (color_text[its_col][1][0]) // That means a <font> was added to the buffer
{
strcat (tagstack,"F");
changed_font++;
}
col = its_col;
}
// Handle underlined
int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
if (is_underlined && underlined==0 && !ccx_options.notypesetting) // Open underline
{
buffer+=encode_line (buffer, (unsigned char *) "<u>");
strcat (tagstack,"U");
underlined++;
}
if (is_underlined==0 && underlined && !ccx_options.notypesetting) // Close underline
{
buffer = close_tag(buffer,tagstack,'U',&underlined,&italics,&changed_font);
}
// Handle italics
int has_ita = data->fonts[line_num][i] & FONT_ITALICS;
if (has_ita && italics==0 && !ccx_options.notypesetting) // Open italics
{
buffer+=encode_line (buffer, (unsigned char *) "<i>");
strcat (tagstack,"I");
italics++;
}
if (has_ita==0 && italics && !ccx_options.notypesetting) // Close italics
{
buffer = close_tag(buffer,tagstack,'I',&underlined,&italics,&changed_font);
}
int bytes=0;
switch (ccx_options.encoding)
{
case CCX_ENC_UTF_8:
bytes=get_char_in_utf_8 (buffer,line[i]);
break;
case CCX_ENC_LATIN_1:
get_char_in_latin_1 (buffer,line[i]);
bytes=1;
break;
case CCX_ENC_UNICODE:
get_char_in_unicode (buffer,line[i]);
bytes=2;
break;
}
buffer+=bytes;
}
buffer = close_tag(buffer,tagstack,'A',&underlined,&italics,&changed_font);
if (underlined || italics || changed_font)
fatal (EXIT_BUG_BUG, "Not all tags closed in encoding, this is a bug, please report.\n");
*buffer=0;
return (unsigned) (buffer-orig); // Return length
}
void delete_all_lines_but_current (struct eia608_screen *data, int row)
{
for (int i=0;i<15;i++)
{
if (i!=row)
{
memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
data->characters[i][CC608_SCREEN_WIDTH]=0;
memset (data->colors[i],ccx_options.cc608_default_color,CC608_SCREEN_WIDTH+1);
memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1);
data->row_used[i]=0;
}
}
}
void fprintf_encoded (FILE *fh, const char *string)
{
REQUEST_BUFFER_CAPACITY(strlen (string)*3);
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) string);
fwrite (enc_buffer,enc_buffer_used,1,fh);
}
void write_cc_buffer_to_gui(struct eia608_screen *data, struct s_context_cc608 *context)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
LLONG ms_start;
int with_data=0;
for (int i=0;i<15;i++)
{
if (data->row_used[i])
with_data=1;
}
if (!with_data)
return;
ms_start= context->current_visible_start_ms;
ms_start+=subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return;
int time_reported=0;
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
fprintf (stderr, "###SUBTITLE#");
if (!time_reported)
{
LLONG ms_end = get_fts()+subs_delay;
mstotime (ms_start,&h1,&m1,&s1,&ms1);
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
// Note, only MM:SS here as we need to save space in the preview window
fprintf (stderr, "%02u:%02u#%02u:%02u#",
h1*60+m1,s1, h2*60+m2,s2);
time_reported=1;
}
else
fprintf (stderr, "##");
// We don't capitalize here because whatever function that was used
// before to write to file already took care of it.
int length = get_decoder_line_encoded_for_gui (subline, i, data);
fwrite (subline, 1, length, stderr);
fwrite ("\n",1,1,stderr);
}
}
fflush (stderr);
}
void try_to_add_end_credits(struct s_context_cc608 *context)
{
LLONG window, length, st, end;
if (context->out->fh == -1)
return;
window=get_fts()-last_displayed_subs_ms-1;
if (window<ccx_options.endcreditsforatleast.time_in_ms) // Won't happen, window is too short
return;
length=ccx_options.endcreditsforatmost.time_in_ms > window ?
window : ccx_options.endcreditsforatmost.time_in_ms;
st=get_fts()-length-1;
end=get_fts();
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
write_stringz_as_srt(ccx_options.end_credits_text, context, st, end);
break;
case CCX_OF_SAMI:
write_stringz_as_sami(ccx_options.end_credits_text, context, st, end);
break;
case CCX_OF_SMPTETT:
write_stringz_as_smptett(ccx_options.end_credits_text, context, st, end);
break ;
default:
// Do nothing for the rest
break;
}
}
void try_to_add_start_credits(struct s_context_cc608 *context)
{
LLONG st, end, window, length;
LLONG l = context->current_visible_start_ms + subs_delay;
// We have a windows from last_displayed_subs_ms to l - we need to see if it fits
if (l<ccx_options.startcreditsnotbefore.time_in_ms) // Too early
return;
if (last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
return;
st = ccx_options.startcreditsnotbefore.time_in_ms>(last_displayed_subs_ms+1) ?
ccx_options.startcreditsnotbefore.time_in_ms : (last_displayed_subs_ms+1); // When would credits actually start
end = ccx_options.startcreditsnotafter.time_in_ms<(l-1) ?
ccx_options.startcreditsnotafter.time_in_ms : (l-1);
window = end-st; // Allowable time in MS
if (ccx_options.startcreditsforatleast.time_in_ms>window) // Window is too short
return;
length=ccx_options.startcreditsforatmost.time_in_ms > window ?
window : ccx_options.startcreditsforatmost.time_in_ms;
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
last_displayed_subs_ms, l);
dbg_print(CCX_DMT_VERBOSE, "Not before: %lld Not after: %lld\n",
ccx_options.startcreditsnotbefore.time_in_ms,
ccx_options.startcreditsnotafter.time_in_ms);
dbg_print(CCX_DMT_VERBOSE, "Start of window: %lld End of window: %lld\n",st,end);
if (window>length+2)
{
// Center in time window
LLONG pad=window-length;
st+=(pad/2);
}
end=st+length;
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
write_stringz_as_srt(ccx_options.start_credits_text,context,st,end);
break;
case CCX_OF_SAMI:
write_stringz_as_sami(ccx_options.start_credits_text, context, st, end);
break;
case CCX_OF_SMPTETT:
write_stringz_as_smptett(ccx_options.start_credits_text, context, st, end);
break;
default:
// Do nothing for the rest
break;
}
startcredits_displayed=1;
return;
}

View File

@@ -1,129 +0,0 @@
#include "ccextractor.h"
void write_stringz_as_sami(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
{
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
(unsigned long long)ms_start);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write (context->out->fh, enc_buffer,enc_buffer_used);
int len=strlen (string);
unsigned char *unescaped= (unsigned char *) malloc (len+1);
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
if (el==NULL || unescaped==NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
int pos_r=0;
int pos_w=0;
// Scan for \n in the string and replace it with a 0
while (pos_r<len)
{
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
{
unescaped[pos_w]=0;
pos_r+=2;
}
else
{
unescaped[pos_w]=string[pos_r];
pos_r++;
}
pos_w++;
}
unescaped[pos_w]=0;
// Now read the unescaped string (now several string'z and write them)
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
unsigned int u = encode_line (el, begin);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r");
dbg_print(CCX_DMT_608, "%s\n",subline);
}
write(context->out->fh, el, u);
write(context->out->fh, encoded_br, encoded_br_length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
(unsigned long long)ms_end);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
}
int write_cc_buffer_as_sami(struct eia608_screen *data, struct s_context_cc608 *context)
{
LLONG startms, endms;
int wrote_something=0;
startms = context->current_visible_start_ms;
startms+=subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = get_visible_end()+subs_delay;
endms--; // To prevent overlapping with next line.
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
(unsigned long long)startms);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write (context->out->fh, enc_buffer,enc_buffer_used);
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r");
dbg_print(CCX_DMT_608, "%s\n",subline);
}
write (context->out->fh, subline, length);
wrote_something=1;
if (i!=14)
write (context->out->fh, encoded_br, encoded_br_length);
write (context->out->fh,encoded_crlf, encoded_crlf_length);
}
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
(unsigned long long)endms);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
return wrote_something;
}

View File

@@ -1,156 +0,0 @@
#include "ccextractor.h"
// Produces minimally-compliant SMPTE Timed Text (W3C TTML)
// format-compatible output
// See http://www.w3.org/TR/ttaf1-dfxp/ and
// https://www.smpte.org/sites/default/files/st2052-1-2010.pdf
// Copyright (C) 2012 John Kemp
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
void write_stringz_as_smptett(char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
mstotime (ms_start,&h1,&m1,&s1,&ms1);
mstotime (ms_end-1,&h2,&m2,&s2,&ms2);
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write (context->out->fh, enc_buffer,enc_buffer_used);
int len=strlen (string);
unsigned char *unescaped= (unsigned char *) malloc (len+1);
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
if (el==NULL || unescaped==NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
int pos_r=0;
int pos_w=0;
// Scan for \n in the string and replace it with a 0
while (pos_r<len)
{
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
{
unescaped[pos_w]=0;
pos_r+=2;
}
else
{
unescaped[pos_w]=string[pos_r];
pos_r++;
}
pos_w++;
}
unescaped[pos_w]=0;
// Now read the unescaped string (now several string'z and write them)
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
unsigned int u = encode_line (el, begin);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r");
dbg_print(CCX_DMT_608, "%s\n",subline);
}
write(context->out->fh, el, u);
//write (wb->fh, encoded_br, encoded_br_length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
sprintf ((char *) str,"</p>\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\">\n\n",h2,m2,s2,ms2);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write (context->out->fh, enc_buffer,enc_buffer_used);
sprintf ((char *) str,"</p>\n");
}
int write_cc_buffer_as_smptett(struct eia608_screen *data, struct s_context_cc608 *context)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
LLONG endms;
int wrote_something=0;
LLONG startms = context->current_visible_start_ms;
startms+=subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = get_visible_end()+subs_delay;
endms--; // To prevent overlapping with next line.
mstotime (startms,&h1,&m1,&s1,&ms1);
mstotime (endms-1,&h2,&m2,&s2,&ms2);
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u,%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r");
dbg_print(CCX_DMT_608, "%s\n",subline);
}
write(context->out->fh, subline, length);
wrote_something=1;
write(context->out->fh, encoded_crlf, encoded_crlf_length);
}
}
sprintf ((char *) str,"</p>\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
write(context->out->fh, enc_buffer, enc_buffer_used);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r%s\n", str);
}
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
//write (wb->fh, enc_buffer,enc_buffer_used);
return wrote_something;
}

View File

@@ -1,195 +0,0 @@
#include "ccextractor.h"
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
if there is any */
void write_stringz_as_srt (char *string, struct s_context_cc608 *context, LLONG ms_start, LLONG ms_end)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
mstotime (ms_start,&h1,&m1,&s1,&ms1);
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
char timeline[128];
context->srt_counter++;
sprintf(timeline, "%u\r\n", context->srt_counter);
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
write(context->out->fh, enc_buffer, enc_buffer_used);
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
h1,m1,s1,ms1, h2,m2,s2,ms2);
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
dbg_print(CCX_DMT_608, "\n- - - SRT caption - - -\n");
dbg_print(CCX_DMT_608, "%s",timeline);
write(context->out->fh, enc_buffer, enc_buffer_used);
int len=strlen (string);
unsigned char *unescaped= (unsigned char *) malloc (len+1);
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
if (el==NULL || unescaped==NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_srt() - not enough memory.\n");
int pos_r=0;
int pos_w=0;
// Scan for \n in the string and replace it with a 0
while (pos_r<len)
{
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
{
unescaped[pos_w]=0;
pos_r+=2;
}
else
{
unescaped[pos_w]=string[pos_r];
pos_r++;
}
pos_w++;
}
unescaped[pos_w]=0;
// Now read the unescaped string (now several string'z and write them)
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
unsigned int u = encode_line (el, begin);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r");
dbg_print(CCX_DMT_608, "%s\n",subline);
}
write(context->out->fh, el, u);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
write(context->out->fh, encoded_crlf, encoded_crlf_length);
free(el);
}
int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_context_cc608 *context)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
LLONG ms_start, ms_end;
int wrote_something = 0;
ms_start = context->current_visible_start_ms;
int prev_line_start=-1, prev_line_end=-1; // Column in which the previous line started and ended, for autodash
int prev_line_center1=-1, prev_line_center2=-1; // Center column of previous line text
int empty_buf=1;
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
empty_buf=0;
break;
}
}
if (empty_buf) // Prevent writing empty screens. Not needed in .srt
return 0;
ms_start+=subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return 0;
ms_end=get_visible_end()+subs_delay;
mstotime (ms_start,&h1,&m1,&s1,&ms1);
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
char timeline[128];
context->srt_counter++;
sprintf(timeline, "%u\r\n", context->srt_counter);
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
write(context->out->fh, enc_buffer, enc_buffer_used);
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
h1,m1,s1,ms1, h2,m2,s2,ms2);
enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
dbg_print(CCX_DMT_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
dbg_print(CCX_DMT_608, "%s",timeline);
write (context->out->fh, enc_buffer,enc_buffer_used);
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
if (ccx_options.sentence_cap)
{
capitalize (i,data);
correct_case(i,data);
}
if (ccx_options.autodash && ccx_options.trim_subs)
{
int first=0, last=31, center1=-1, center2=-1;
unsigned char *line = data->characters[i];
int do_dash=1, colon_pos=-1;
find_limit_characters(line,&first,&last);
if (first==-1 || last==-1) // Probably a bug somewhere though
break;
// Is there a speaker named, for example: TOM: What are you doing?
for (int j=first;j<=last;j++)
{
if (line[j]==':')
{
colon_pos=j;
break;
}
if (!isupper (line[j]))
break;
}
if (prev_line_start==-1)
do_dash=0;
if (first==prev_line_start) // Case of left alignment
do_dash=0;
if (last==prev_line_end) // Right align
do_dash=0;
if (first>prev_line_start && last<prev_line_end) // Fully contained
do_dash=0;
if ((first>prev_line_start && first<prev_line_end) || // Overlap
(last>prev_line_start && last<prev_line_end))
do_dash=0;
center1=(first+last)/2;
if (colon_pos!=-1)
{
while (colon_pos<CC608_SCREEN_WIDTH &&
(line[colon_pos]==':' ||
line[colon_pos]==' ' ||
line[colon_pos]==0x89))
colon_pos++; // Find actual text
center2=(colon_pos+last)/2;
}
else
center2=center1;
if (center1>=prev_line_center1-1 && center1<=prev_line_center1+1 && center1!=-1) // Center align
do_dash=0;
if (center2>=prev_line_center2-2 && center1<=prev_line_center2+2 && center1!=-1) // Center align
do_dash=0;
if (do_dash)
write(context->out->fh, "- ", 2);
prev_line_start=first;
prev_line_end=last;
prev_line_center1=center1;
prev_line_center2=center2;
}
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_608, "\r");
dbg_print(CCX_DMT_608, "%s\n",subline);
}
write(context->out->fh, subline, length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
wrote_something=1;
// fprintf (wb->fh,encoded_crlf);
}
}
dbg_print(CCX_DMT_608, "- - - - - - - - - - - -\r\n");
// fprintf (wb->fh, encoded_crlf);
write (context->out->fh, encoded_crlf, encoded_crlf_length);
return wrote_something;
}

View File

@@ -0,0 +1,6 @@
/**
* the configured options and settings for CCExtractor
*/
#define CCExtractor_VERSION_MAJOR @CCEXTRACTOR_VERSION_MAJOR@
#define CCExtractor_VERSION_MINOR @CCEXTRACTOR_VERSION_MINOR@

54
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,54 @@
cmake_minimum_required (VERSION 3.0.2)
project (CCExtractor)
option(WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF)
#Version number
set (CCEXTRACTOR_VERSION_MAJOR 0)
set (CCEXTRACTOR_VERSION_MINOR 75)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
"${PROJECT_SOURCE_DIR}/CCExtractorConfig.h.in"
"${PROJECT_BINARY_DIR}/CCExtractorConfig.h"
)
include_directories ("${PROJECT_SOURCE_DIR}")
include_directories ("${PROJECT_SOURCE_DIR}/lib_ccx")
include_directories ("${PROJECT_SOURCE_DIR}/gpacmp4/")
include_directories ("${PROJECT_SOURCE_DIR}/libccx_common/")
#Adding some platform specific library path
LINK_DIRECTORIES(/opt/local/lib)
LINK_DIRECTORIES(/usr/local/lib)
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -g -std=gnu99 -Wno-write-strings -D_FILE_OFFSET_BITS=64")
add_subdirectory (lib_ccx)
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} SOURCEFILE)
set (EXTRA_LIBS ${EXTRA_LIBS} ccx)
set (EXTRA_LIBS ${EXTRA_LIBS} png)
set (EXTRA_LIBS ${EXTRA_LIBS} m)
########################################################
# Build using FFmpeg libraries
#
if (WITH_FFMPEG)
find_package(PkgConfig)
pkg_check_modules(AVFORMAT REQUIRED libavformat)
pkg_check_modules(AVUTIL REQUIRED libavutil)
pkg_check_modules(AVCODEC REQUIRED libavcodec)
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVFORMAT_STATIC_LIBRARIES} )
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVUTIL_STATIC_LIBRARIES} )
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVCODEC_STATIC_LIBRARIES} )
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
endif (WITH_FFMPEG)
add_executable(ccextractor ${SOURCEFILE})
target_link_libraries (ccextractor ${EXTRA_LIBS})
install (TARGETS ccextractor DESTINATION bin)

View File

@@ -1,25 +0,0 @@
/* Functions used by both the 608 and 708 decoders. An effort should be
made to reuse, not duplicate, as many functions as possible */
#include "ccextractor.h"
/* This function returns a FTS that is guaranteed to be at least 1 ms later than the end of the previous screen. It shouldn't be needed
obviously but it guarantees there's no timing overlap */
LLONG get_visible_start (void)
{
LLONG fts = get_fts();
if (fts <= minimum_fts)
fts = minimum_fts+1;
dbg_print(CCX_DMT_608, "Visible Start time=%s\n", print_mstime(fts));
return fts;
}
/* This function returns the current FTS and saves it so it can be used by get_visible_start */
LLONG get_visible_end (void)
{
LLONG fts = get_fts();
if (fts>minimum_fts)
minimum_fts=fts;
dbg_print(CCX_DMT_608, "Visible End time=%s\n", print_mstime(fts));
return fts;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,605 +0,0 @@
#ifndef CCX_CCEXTRACTOR_H
#define CCX_CCEXTRACTOR_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
// compatibility across platforms
#include "platform.h"
#define VERSION "0.70"
extern int cc_buffer_saved; // Do we have anything in the CC buffer already?
extern int ccblocks_in_avc_total; // Total CC blocks found by the AVC code
extern int ccblocks_in_avc_lost; // CC blocks found by the AVC code lost due to overwrites (should be 0)
#include "608.h"
#include "708.h"
#include "bitstream.h"
#include "constants.h"
#define TS_PMT_MAP_SIZE 128
struct ccx_boundary_time
{
int hh,mm,ss;
LLONG time_in_ms;
int set;
};
typedef struct {
// TODO: add more options, and (perhaps) reduce other ccextractor options?
int showStartTime, showEndTime; // Show start and/or end time.
int showMode; // Show which mode if available (E.G.: POP, RU1, ...)
int showCC; // Show which CC channel has been captured.
int relativeTimestamp; // Timestamps relative to start of sample or in UTC?
int xds; // Show XDS or not
int useColors; // Add colors or no colors
} ccx_transcript_format;
extern ccx_transcript_format ccx_default_transcript_settings;
struct ccx_s_options // Options from user parameters
{
int extract; // Extract 1st, 2nd or both fields
int cc_channel; // Channel we want to dump in srt mode
int buffer_input;
int direct_rollup;
int nofontcolor;
int notypesetting;
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
int print_file_reports;
/* subtitle codec type */
enum cxx_code_type codec;
enum cxx_code_type nocodec;
/* Credit stuff */
char *start_credits_text;
char *end_credits_text;
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
int binary_concat; // Disabled by -ve or --videoedited
int use_gop_as_pts; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
int norollup; // If 1, write one line at a time
int forced_ru; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
int trim_subs; // " Remove spaces at sides? "
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
int no_progress_bar; // If 1, suppress the output of the progress to stdout
int sentence_cap ; // FIX CASE? = Fix case?
char *sentence_cap_file; // Extra words file?
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
0 -> A regular file
>0 -> Live stream with a timeout of this value in seconds */
int messages_target; // 0 = nowhere (quiet), 1=stdout, 2=stderr
/* Levenshtein's parameters, for string comparison */
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
int investigate_packets; // Look for captions in all packets when everything else fails
int fullbin; // Disable pruning of padding cc blocks
int nosync; // Disable syncing
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
int wtvconvertfix; // Fix broken Windows 7 conversion
int wtvmpeg2;
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
/* MP4 related stuff */
unsigned mp4vidtrack; // Process the video track even if a CC dedicated track exists.
/* General settings */
int usepicorder; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
int autodash; // Add dashes (-) before each speaker automatically?
unsigned teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
ccx_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
char millis_separator;
LLONG screens_to_process; // How many screenfuls we want?
enum ccx_encoding_type encoding;
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
enum ccx_output_date_format date_format;
enum color_code cc608_default_color;
char *output_filename;
char *out_elementarystream_filename;
LLONG debug_mask; // dbg_print will use this mask to print or ignore different types
LLONG debug_mask_on_debug; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
unsigned ts_autoprogram ; // Try to find a stream with captions automatically (no -pn needed)
unsigned ts_cappid ; // PID for stream that holds caption information
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
unsigned ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
unsigned ts_forced_program_selected;
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
unsigned ts_forced_streamtype; // User selected (forced) stream type
/* Networking */
in_addr_t udpaddr;
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
int line_terminator_lf; // 0 = CRLF, 1=LF
int noautotimeref; // Do NOT set time automatically?
enum ccx_datasource input_source; // Files, stdin or network
};
struct ts_payload
{
unsigned char *start; // Payload start
unsigned length; // Payload length
unsigned pesstart; // PES or PSI start
unsigned pid; // Stream PID
int counter; // continuity counter
int transport_error; // 0 = packet OK, non-zero damaged
unsigned char section_buf[1024];
int section_index;
int section_size;
};
struct PAT_entry
{
unsigned program_number;
unsigned PMT_PID;
unsigned char *last_pmt_payload;
unsigned last_pmt_length;
};
struct PMT_entry
{
unsigned program_number;
unsigned PMT_PID;
unsigned elementary_PID;
unsigned ccx_stream_type;
unsigned printable_stream_type;
};
struct ccx_s_write
{
int fh;
char *filename;
void* spupng_data;
};
struct gop_time_code
{
int drop_frame_flag;
int time_code_hours;
int time_code_minutes;
int marker_bit;
int time_code_seconds;
int time_code_pictures;
int inited;
LLONG ms;
};
/* Report information */
#define SUB_STREAMS_CNT 10
struct file_report_t
{
unsigned program_cnt;
unsigned width;
unsigned height;
unsigned aspect_ratio;
unsigned frame_rate;
unsigned xds : 1;
unsigned cc_channels_608[4];
unsigned services708[63];
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
unsigned mp4_cc_track_cnt;
} file_report;
// Stuff for telcc.c
struct ccx_s_teletext_config {
uint8_t verbose : 1; // should telxcc be verbose?
uint16_t page; // teletext page containing cc we want to filter
uint16_t tid; // 13-bit packet ID for teletext stream
double offset; // time offset in seconds
uint8_t bom : 1; // print UTF-8 BOM characters at the beginning of output
uint8_t nonempty : 1; // produce at least one (dummy) frame
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
// uint64_t utc_refvalue; // UTC referential value => Moved to CCExtractor global, so can be used for 608 too
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
};
#define buffered_skip(bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
filebuffer_pos+=bytes; \
result=bytes; \
} else result=buffered_read_opt (NULL,bytes);
#define buffered_read(buffer,bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
if (buffer!=NULL) memcpy (buffer,filebuffer+filebuffer_pos,bytes); \
filebuffer_pos+=bytes; \
result=bytes; \
} else { result=buffered_read_opt (buffer,bytes); if (ccx_options.gui_mode_reports && ccx_options.input_source==CCX_DS_NETWORK) {net_activity_gui++; if (!(net_activity_gui%1000))activity_report_data_read();}}
#define buffered_read_4(buffer) if (4<=bytesinbuffer-filebuffer_pos) { \
if (buffer) { buffer[0]=filebuffer[filebuffer_pos]; \
buffer[1]=filebuffer[filebuffer_pos+1]; \
buffer[2]=filebuffer[filebuffer_pos+2]; \
buffer[3]=filebuffer[filebuffer_pos+3]; \
filebuffer_pos+=4; \
result=4; } \
} else result=buffered_read_opt (buffer,4);
#define buffered_read_byte(buffer) if (bytesinbuffer-filebuffer_pos) { \
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
filebuffer_pos++; \
result=1; } \
} else result=buffered_read_opt (buffer,1);
extern LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes);
//params.c
void parse_parameters (int argc, char *argv[]);
void usage (void);
int atoi_hex (char *s);
int stringztoms (const char *s, struct ccx_boundary_time *bt);
// general_loop.c
void position_sanity_check ();
int init_file_buffer( void );
LLONG ps_getmoredata( void );
LLONG general_getmoredata( void );
void raw_loop (void);
LLONG process_raw (void);
void general_loop(void);
void processhex (char *filename);
void rcwt_loop( void );
#ifndef __cplusplus
#define false 0
#define true 1
#endif
// activity.c
void activity_header (void);
void activity_progress (int percentaje, int cur_min, int cur_sec);
void activity_report_version (void);
void activity_input_file_closed (void);
void activity_input_file_open (const char *filename);
void activity_message (const char *fmt, ...);
void activity_video_info (int hor_size,int vert_size,
const char *aspect_ratio, const char *framerate);
void activity_program_number (unsigned program_number);
void activity_xds_program_name (const char *program_name);
void activity_xds_network_call_letters (const char *program_name);
void activity_xds_program_identification_number (unsigned minutes, unsigned hours, unsigned date, unsigned month);
void activity_xds_program_description (int line_num, const char *program_desc);
void activity_report_data_read (void);
extern LLONG result;
extern int end_of_file;
extern LLONG inbuf;
extern int ccx_bufferdatatype; // Can be RAW or PES
// asf_functions.c
LLONG asf_getmoredata( void );
// wtv_functions.c
LLONG wtv_getmoredata( void );
// avc_functions.c
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen);
void init_avc(void);
// es_functions.c
LLONG process_m2v (unsigned char *data, LLONG length);
extern unsigned top_field_first;
// es_userdata.c
int user_data(struct bitstream *ustream, int udtype);
// bitstream.c - see bitstream.h
// 608.c
int write_cc_buffer(struct s_context_cc608 *context);
unsigned char *debug_608toASC (unsigned char *ccdata, int channel);
// cc_decoders_common.c
LLONG get_visible_start (void);
LLONG get_visible_end (void);
// file_functions.c
LLONG getfilesize (int in);
LLONG gettotalfilessize (void);
void prepare_for_new_file (void);
void close_input_file (void);
int switch_to_next_file (LLONG bytesinbuffer);
int init_sockets (void);
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
// timing.c
void set_fts(void);
LLONG get_fts(void);
LLONG get_fts_max(void);
char *print_mstime( LLONG mstime );
char *print_mstime2buf( LLONG mstime , char *buf );
void print_debug_timing( void );
int gop_accepted(struct gop_time_code* g );
void calculate_ms_gop_time (struct gop_time_code *g);
// sequencing.c
void init_hdcc (void);
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts);
void anchor_hdcc(int seq);
void process_hdcc (void);
int do_cb (unsigned char *cc_block);
// mp4.c
int processmp4 (char *file);
// params_dump.c
void params_dump(void);
void print_file_report(void);
// output.c
void init_write (struct ccx_s_write *wb);
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context);
void flushbuffer (struct ccx_s_write *wb, int closefile);
void printdata (const unsigned char *data1, int length1,const unsigned char *data2, int length2);
void writercwtdata (const unsigned char *data);
// stream_functions.c
void detect_stream_type (void);
int detect_myth( void );
int read_video_pes_header (unsigned char *header, int *headerlength, int sbuflen);
int read_pts_pes(unsigned char*header, int len);
// ts_functions.c
void init_ts( void );
int ts_readpacket(void);
long ts_readstream(void);
LLONG ts_getmoredata( void );
int write_section(struct ts_payload *payload, unsigned char*buf, int size, int pos);
int parse_PMT (unsigned char *buf,int len, int pos);
int parse_PAT (void);
// myth.c
void myth_loop(void);
// mp4_bridge2bento4.c
void mp4_loop (char *filename);
// xds.c
void process_xds_bytes (const unsigned char hi, int lo);
void do_end_of_xds (unsigned char expected_checksum);
void xds_init();
// ccextractor.c
LLONG calculate_gop_mstime (struct gop_time_code *g);
void set_fts(void);
char *print_mstime( LLONG mstime );
void print_debug_timing( void );
int switch_to_next_file (LLONG bytesinbuffer);
// utility.c
void fatal(int exit_code, const char *fmt, ...);
void dvprint(const char *fmt, ...);
void mprint (const char *fmt, ...);
void subsprintf (const char *fmt, ...);
void dbg_print(LLONG mask, const char *fmt, ...);
void fdprintf (int fd, const char *fmt, ...);
void init_boundary_time (struct ccx_boundary_time *bt);
void sleep_secs (int secs);
void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, unsigned clear_high_bit);
bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) ;
int hex2int (char high, char low);
void timestamp_to_srttime(uint64_t timestamp, char *buffer);
void millis_to_date (uint64_t timestamp, char *buffer) ;
int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len);
void init_context_cc608(struct s_context_cc608 *data, int field);
unsigned encode_line (unsigned char *buffer, unsigned char *text);
void buffered_seek (int offset);
void write_subtitle_file_header(struct ccx_s_write *out);
void write_subtitle_file_footer(struct ccx_s_write *out);
extern void build_parity_table(void);
void tlt_process_pes_packet(uint8_t *buffer, uint16_t size) ;
void telxcc_init(void);
void telxcc_close(void);
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,
unsigned *seconds, unsigned *ms);
extern struct gop_time_code gop_time, first_gop_time, printed_gop;
extern int gop_rollover;
extern LLONG min_pts, sync_pts, current_pts;
extern unsigned rollover_bits;
extern uint32_t global_timestamp, min_global_timestamp;
extern int global_timestamp_inited;
extern LLONG fts_now; // Time stamp of current file (w/ fts_offset, w/o fts_global)
extern LLONG fts_offset; // Time before first sync_pts
extern LLONG fts_fc_offset; // Time before first GOP
extern LLONG fts_max; // Remember the maximum fts that we saw in current file
extern LLONG fts_global; // Duration of previous files (-ve mode)
// Count 608 (per field) and 708 blocks since last set_fts() call
extern int cb_field1, cb_field2, cb_708;
extern int saw_caption_block;
extern unsigned char *buffer;
extern LLONG past;
extern LLONG total_inputsize, total_past; // Only in binary concat mode
extern char **inputfile;
extern int current_file;
extern LLONG result; // Number of bytes read/skipped in last read operation
extern struct sockaddr_in servaddr, cliaddr;
extern int strangeheader;
extern unsigned char startbytes[STARTBYTESLENGTH];
extern unsigned int startbytes_pos;
extern int startbytes_avail; // Needs to be able to hold -1 result.
extern unsigned char *pesheaderbuf;
extern int pts_set; //0 = No, 1 = received, 2 = min_pts set
extern unsigned long long max_dif;
extern int MPEG_CLOCK_FREQ; // This is part of the standard
extern unsigned pts_big_change;
extern unsigned total_frames_count;
extern unsigned total_pulldownfields;
extern unsigned total_pulldownframes;
extern int CaptionGap;
extern unsigned char *filebuffer;
extern LLONG filebuffer_start; // Position of buffer start relative to file
extern int filebuffer_pos; // Position of pointer relative to buffer start
extern int bytesinbuffer; // Number of bytes we actually have on buffer
extern struct s_context_cc608 context_cc608_field_1, context_cc608_field_2;
extern const char *desc[256];
extern FILE *fh_out_elementarystream;
extern int infd;
extern int false_pict_header;
extern int stat_numuserheaders;
extern int stat_dvdccheaders;
extern int stat_scte20ccheaders;
extern int stat_replay5000headers;
extern int stat_replay4000headers;
extern int stat_dishheaders;
extern int stat_hdtv;
extern int stat_divicom;
extern enum ccx_stream_mode_enum stream_mode;
extern int cc_stats[4];
extern LLONG inputsize;
extern LLONG subs_delay;
extern int startcredits_displayed, end_credits_displayed;
extern LLONG last_displayed_subs_ms;
extern int processed_enough;
extern unsigned char usercolor_rgb[8];
extern const char *extension;
extern long FILEBUFFERSIZE; // Uppercase because it used to be a define
extern struct ccx_s_options ccx_options;
extern int temp_debug;
extern unsigned long net_activity_gui;
/* General (ES stream) video information */
extern unsigned current_hor_size;
extern unsigned current_vert_size;
extern unsigned current_aspect_ratio;
extern unsigned current_frame_rate;
extern double current_fps;
extern int end_of_file;
extern LLONG inbuf;
extern enum ccx_bufferdata_type bufferdatatype; // Can be CCX_BUFFERDATA_TYPE_RAW or CCX_BUFFERDATA_TYPE_PES
extern unsigned top_field_first;
extern int firstcall;
extern LLONG minimum_fts; // No screen should start before this FTS
#define MAXBFRAMES 50
#define SORTBUF (2*MAXBFRAMES+1)
extern int cc_data_count[SORTBUF];
extern unsigned char cc_data_pkts[SORTBUF][10*31*3+1];
extern int has_ccdata_buffered;
extern int current_field;
extern int last_reported_progress;
extern int cc_to_stdout;
extern unsigned hauppauge_warning_shown;
extern unsigned char *subline;
extern int saw_gop_header;
extern int max_gop_length;
extern int last_gop_length;
extern int frames_since_last_gop;
extern LLONG fts_at_gop_start;
extern int frames_since_ref_time;
extern enum ccx_stream_mode_enum auto_stream;
extern int num_input_files;
extern char *basefilename;
extern int do_cea708; // Process 708 data?
extern int cea708services[63]; // [] -> 1 for services to be processed
extern struct ccx_s_write wbout1, wbout2, *wbxdsout;
extern char **spell_lower;
extern char **spell_correct;
extern int spell_words;
extern int spell_capacity;
extern unsigned char encoded_crlf[16]; // We keep it encoded here so we don't have to do it many times
extern unsigned int encoded_crlf_length;
extern unsigned char encoded_br[16];
extern unsigned int encoded_br_length;
extern enum ccx_frame_type current_picture_coding_type;
extern int current_tref; // Store temporal reference of current frame
extern int cc608_parity_table[256]; // From myth
// From ts_functions
extern unsigned cap_stream_type;
extern struct ts_payload payload;
extern unsigned char tspacket[188];
extern struct PAT_entry pmt_array[TS_PMT_MAP_SIZE];
extern uint16_t pmt_array_length;
extern unsigned pmtpid;
extern unsigned TS_program_number;
extern unsigned char *last_pat_payload;
extern unsigned last_pat_length;
extern long capbuflen;
#define HAUPPAGE_CCPID 1003 // PID for CC's in some Hauppauge recordings
/* Exit codes. Take this seriously as the GUI depends on them.
0 means OK as usual,
<100 means display whatever was output to stderr as a warning
>=100 means display whatever was output to stdout as an error
*/
#define EXIT_OK 0
#define EXIT_NO_INPUT_FILES 2
#define EXIT_TOO_MANY_INPUT_FILES 3
#define EXIT_INCOMPATIBLE_PARAMETERS 4
#define EXIT_FILE_CREATION_FAILED 5
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
#define EXIT_MALFORMED_PARAMETER 7
#define EXIT_READ_ERROR 8
#define EXIT_UNSUPPORTED 9
#define EXIT_NOT_CLASSIFIED 300
#define EXIT_NOT_ENOUGH_MEMORY 500
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
#define EXIT_BUFFER_FULL 502
#define EXIT_BUG_BUG 1000
#define EXIT_MISSING_ASF_HEADER 1001
#define EXIT_MISSING_RCWT_HEADER 1002
extern int PIDs_seen[65536];
extern struct PMT_entry *PIDs_programs[65536];
extern LLONG ts_start_of_xds;
//extern int timestamps_on_transcript;
extern unsigned teletext_mode;
#define MAX_TLT_PAGES 1000
extern short int seen_sub_page[MAX_TLT_PAGES];
extern uint64_t utc_refvalue; // UTC referential value
extern struct ccx_s_teletext_config tlt_config;
extern uint32_t tlt_packet_counter;
extern uint32_t tlt_frames_produced;
#endif

View File

@@ -25,7 +25,7 @@
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/setup.h>
#ifndef GPAC_DISABLE_AVILIB

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#ifndef GPAC_DISABLE_ISOM

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#ifndef GPAC_DISABLE_ISOM

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#include <gpac/network.h>

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/odf_dev.h>
#include <gpac/constants.h>

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/tools.h>

View File

@@ -22,7 +22,7 @@
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/odf_dev.h>
#ifndef GPAC_MINIMAL_ODF

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#include <gpac/network.h>
#ifndef _WIN32
@@ -398,23 +398,6 @@ GF_ISOFile *gf_isom_open_file(const char *fileName, u32 OpenMode, const char *tm
return mov;
}
#ifndef WIN32
void gf_utc_time_since_1970(u32 *sec, u32 *msec)
{
#if defined (WIN32) && !defined(_WIN32_WCE)
struct _timeb tb;
_ftime( &tb );
*sec = (u32) tb.time;
*msec = tb.millitm;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
*sec = tv.tv_sec;
*msec = tv.tv_usec/1000;
#endif
}
#endif
u64 gf_isom_get_mp4time()
{
u32 calctime, msec;

View File

@@ -22,7 +22,7 @@
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#include <gpac/constants.h>

View File

@@ -22,7 +22,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#include <gpac/constants.h>

View File

@@ -23,7 +23,7 @@
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#ifndef GPAC_DISABLE_ISOM

View File

@@ -3,9 +3,12 @@
#include <stdlib.h>
#include <gpac/isomedia.h>
#include "../ccextractor.h"
#include "lib_ccx.h"
#include "utility.h"
#include "ccx_encoders_common.h"
#include "ccx_common_option.h"
void do_NAL (unsigned char *NALstart, LLONG NAL_length); // From avc_functions.c
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
static short bswap16(short v)
@@ -24,14 +27,14 @@ static struct {
unsigned type[32];
}s_nalu_stats;
static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s)
static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
{
int status = 0;
u32 i;
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
if (pts_set==0)
if (pts_set==0)
pts_set=1;
set_fts();
@@ -59,19 +62,20 @@ static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s)
temp_debug=0;
if (nal_length>0)
do_NAL ((unsigned char *) &(s->data[i]) ,nal_length);
do_NAL (ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
i += nal_length;
} // outer for
assert(i == s->dataLength);
return status;
}
static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
{
u32 timescale, i, sample_count;
int status;
if((sample_count = gf_isom_get_sample_count(f, track)) < 1){
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
{
return 0;
}
@@ -79,29 +83,30 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
status = 0;
for(i = 0; i < sample_count; i++){
for(i = 0; i < sample_count; i++)
{
u32 sdi;
GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
if (s!=NULL) {
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
current_pts=(LLONG )(s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale ; // Convert frequency to official one
if (pts_set==0)
pts_set=1;
set_fts();
if (s!=NULL)
{
s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
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();
process_m2v ((unsigned char *) s->data,s->dataLength);
process_m2v (ctx, (unsigned char *) s->data,s->dataLength, sub);
gf_isom_sample_del(&s);
}
int progress = (int) ((i*100) / sample_count);
if (last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
last_reported_progress = progress;
}
int progress = (int) ((i*100) / sample_count);
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
activity_progress(100, cur_sec/60, cur_sec%60);
@@ -109,13 +114,14 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track)
return status;
}
static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
{
u32 timescale, i, sample_count, last_sdi = 0;
int status;
GF_AVCConfig* c = NULL;
if((sample_count = gf_isom_get_sample_count(f, track)) < 1){
if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
{
return 0;
}
@@ -123,19 +129,24 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
status = 0;
for(i = 0; i < sample_count; i++){
for(i = 0; i < sample_count; i++)
{
u32 sdi;
GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
if(s != NULL){
if(sdi != last_sdi){
if(c != NULL){
if(s != NULL)
{
if(sdi != last_sdi)
{
if(c != NULL)
{
gf_odf_avc_cfg_del(c);
c = NULL;
}
if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL){
if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL)
{
gf_isom_sample_del(&s);
status = -1;
break;
@@ -144,27 +155,29 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
last_sdi = sdi;
}
status = process_avc_sample(timescale, c, s);
status = process_avc_sample(ctx, timescale, c, s, sub);
gf_isom_sample_del(&s);
if(status != 0){
if(status != 0)
{
break;
}
}
int progress = (int) ((i*100) / sample_count);
if (last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
last_reported_progress = progress;
}
int progress = (int) ((i*100) / sample_count);
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
activity_progress(100, cur_sec/60, cur_sec%60);
if(c != NULL){
if(c != NULL)
{
gf_odf_avc_cfg_del(c);
c = NULL;
}
@@ -180,19 +193,25 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track)
if track is AVC track
for each sample in track
for each NALU in sample
send to avc.cpp for processing
send to avc.c for processing
close(media)
}
*/
int processmp4 (char *file)
int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
{
GF_ISOFile* f;
u32 i, j, track_count, avc_track_count, cc_track_count;
mprint("opening \'%s\': ", file);
struct cc_subtitle dec_sub;
if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL){
memset(&dec_sub,0,sizeof(dec_sub));
mprint("opening \'%s\': ", file);
#ifdef MP4_DEBUG
gf_log_set_tool_level(GF_LOG_CONTAINER,GF_LOG_DEBUG);
#endif
if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL)
{
mprint("failed to open\n");
return -2;
}
@@ -218,7 +237,8 @@ int processmp4 (char *file)
avc_track_count++;
}
for(i = 0; i < track_count; i++){
for(i = 0; i < track_count; i++)
{
const u32 type = gf_isom_get_media_type(f, i + 1);
const u32 subtype = gf_isom_get_media_subtype(f, i + 1, 1);
@@ -226,10 +246,17 @@ int processmp4 (char *file)
{
if (cc_track_count && !ccx_options.mp4vidtrack)
continue;
if(process_xdvb_track(file, f, i + 1) != 0){
if(process_xdvb_track(ctx, file, f, i + 1, &dec_sub) != 0)
{
mprint("error\n");
return -3;
} }
}
if(dec_sub.got_output)
{
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
}
}
if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
{
@@ -240,15 +267,21 @@ int processmp4 (char *file)
{
for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
{
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
do_NAL ((unsigned char *) seqcnf->data,seqcnf->size);
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
do_NAL (ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
}
}
if(process_avc_track(file, f, i + 1) != 0){
if(process_avc_track(ctx, file, f, i + 1, &dec_sub) != 0)
{
mprint("error\n");
return -3;
}
if(dec_sub.got_output)
{
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
}
}
@@ -257,16 +290,20 @@ int processmp4 (char *file)
if (avc_track_count && ccx_options.mp4vidtrack)
continue;
/* unsigned num_streams = gf_isom_get_sample_description_count (f,i+1); */
#ifdef MP4_DEBUG
unsigned num_streams = gf_isom_get_sample_description_count (f,i+1);
#endif
unsigned num_samples = gf_isom_get_sample_count (f,i+1);
u32 ProcessingStreamDescriptionIndex = 0; // Current track we are processing, 0 = we don't know yet
u32 timescale = gf_isom_get_media_timescale(f,i+1);
// u64 duration = gf_isom_get_media_duration(f,i+1);
/* mprint ("%u streams\n",num_streams);
#ifdef MP$DEBUG
u64 duration = gf_isom_get_media_duration(f,i+1);
mprint ("%u streams\n",num_streams);
mprint ("%u sample counts\n",num_samples);
mprint ("%u timescale\n",(unsigned) timescale);
mprint ("%u duration\n",(unsigned) duration); */
mprint ("%u duration\n",(unsigned) duration);
#endif
for (unsigned k = 0; k <num_samples; k++)
{
u32 StreamDescriptionIndex;
@@ -281,48 +318,59 @@ int processmp4 (char *file)
ProcessingStreamDescriptionIndex=StreamDescriptionIndex;
if (sample==NULL)
continue;
// mprint ("Data length: %lu\n",sample->dataLength);
/* const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale; */
#ifdef DEBUG
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();
// Change by Willem
// Apparently the first 4 bytes are the sample length, and then comes 'cdat', and then the data itself
/*if (sample->dataLength>8 && strncmp (sample->data+4, "cdat", 4)==0)
int atomStart = 0;
// process Atom by Atom
while (atomStart < sample->dataLength)
{
//dump (256,( unsigned char *) sample->data+8,sample->dataLength-8,0, 1);
process608((const unsigned char *)sample->data + 8, sample->dataLength - 8, &context_cc608_field_1);
}*/
// Based on https://developer.apple.com/library/prerelease/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW87
// An atom consists of the Atom size, Atom Type and the data.
// First 4 bytes are length in bytes of this atom
// byte 5-8 are the atom type. Should be either cdat or cdt2
// byte 9-x are actual data.
// This means a sample can contain multiple atoms!
if (sample->dataLength > 8 && strncmp(sample->data + 4, "cdat", 4) == 0){ // The format of the closed captioning sample data is a sequence of one or more atoms, one of which must be a 'cdat' atom.
int atomStart = 0;
// process Atom by Atom
while (atomStart < sample->dataLength){
unsigned int atomLength = (unsigned char)sample->data[atomStart] << 24 | (unsigned char)sample->data[atomStart + 1] << 16 | (unsigned char)sample->data[atomStart + 2] << 8 | (unsigned char)sample->data[atomStart + 3];
if (atomLength > 8 && (strncmp(sample->data + atomStart + 4, "cdat", 4) == 0 || strncmp(sample->data + atomStart + 4, "cdt2", 4) == 0)){
dump(256, (unsigned char *)sample->data +atomStart+ 8, atomLength - 8, 0, 1);
process608((const unsigned char *)sample->data + atomStart + 8, atomLength - 8, &context_cc608_field_1);
}
atomStart += atomLength;
char *data = sample->data + atomStart;
unsigned int atomLength = RB32(data);
if(atomLength < 8 || atomLength > sample->dataLength)
{
mprint ("Invalid atom.\n");
break;
}
data += 4;
if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4))
{
int ret = 0;
int len = atomLength - 8;
data += 4;
#ifdef MP4_DEBUG
dump(256, (unsigned char *)data, atomLength - 8, 0, 1);
#endif
do
{
ret = process608((unsigned char*)data, len, ctx->dec_ctx->context_cc608_field_1, &dec_sub);
len -= ret;
data += ret;
if(dec_sub.got_output)
{
encode_sub(enc_ctx, &dec_sub);
dec_sub.got_output = 0;
}
} while (len > 0);
}
atomStart += atomLength;
}
// End of change
int progress = (int) ((k*100) / num_samples);
if (last_reported_progress != progress)
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
last_reported_progress = progress;
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
@@ -336,9 +384,12 @@ int processmp4 (char *file)
f = NULL;
mprint ("ok\n");
if(avc_track_count == 0){
if(avc_track_count == 0)
{
mprint("Found no AVC track(s). ", file);
}else{
}
else
{
mprint("Found %d AVC track(s). ", avc_track_count);
}
if (cc_track_count)
@@ -346,9 +397,9 @@ int processmp4 (char *file)
else
mprint ("found no dedicated CC track(s).\n");
file_report.mp4_cc_track_cnt = cc_track_count;
ctx->freport.mp4_cc_track_cnt = cc_track_count;
if (ccx_options.print_file_reports)
print_file_report();
print_file_report(ctx);
return 0;
}

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/tools.h>
#if defined(_WIN32_WCE)

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#ifndef GPAC_DISABLE_ISOM

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#include <gpac/constants.h>

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/internal/isomedia_dev.h>
#include <gpac/constants.h>

View File

@@ -21,7 +21,7 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "../disable_warnings.h"
#include "disable_warnings.h"
#include <gpac/network.h>
/* the length of the URL separator ("://" || "|//") */

204
src/lib_ccx/608_sami.c Normal file
View File

@@ -0,0 +1,204 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "png.h"
#include "spupng_encoder.h"
#include "ocr.h"
#include "utility.h"
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
int used;
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
int len=strlen (string);
unsigned char *unescaped= (unsigned char *) malloc (len+1);
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
if (el==NULL || unescaped==NULL)
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
int pos_r=0;
int pos_w=0;
// Scan for \n in the string and replace it with a 0
while (pos_r<len)
{
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
{
unescaped[pos_w]=0;
pos_r+=2;
}
else
{
unescaped[pos_w]=string[pos_r];
pos_r++;
}
pos_w++;
}
unescaped[pos_w]=0;
// Now read the unescaped string (now several string'z and write them)
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
unsigned int u = encode_line (el, begin);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write(context->out->fh, el, u);
write(context->out->fh, encoded_br, encoded_br_length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used=encode_line (context->buffer,(unsigned char *) str);
write(context->out->fh, context->buffer, used);
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
(unsigned long long)ms_end);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
write(context->out->fh, context->buffer, used);
free(el);
free(unescaped);
}
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_bitmap* rect;
LLONG ms_start, ms_end;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + context->subs_delay;
ms_end = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time + context->subs_delay;
ms_end = sub->end_time - 1;
}
else if ( context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER) )
{
ms_start = 1 + context->subs_delay;
ms_end = sub->start_time - 1;
}
if(sub->nb_data == 0 )
return 0;
rect = sub->data;
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
#if ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *token = NULL;
char *buf = (char*)context->buffer;
sprintf(buf,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
,(unsigned long long)ms_start);
write(context->out->fh, buf, strlen(buf));
token = strtok(rect[0].ocr_text,"\r\n");
while (token)
{
sprintf(buf, "%s", token);
token = strtok(NULL,"\r\n");
if(token)
strcat(buf, "<br>\n");
else
strcat(buf, "\n");
write(context->out->fh, buf, strlen(buf));
}
sprintf(buf,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n"
,(unsigned long long)ms_end);
write(context->out->fh, buf, strlen(buf));
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
return ret;
}
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context)
{
int used;
LLONG startms, endms;
int wrote_something=0;
startms = data->start_time;
startms+=context->subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
endms = data->end_time;
endms--; // To prevent overlapping with next line.
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
(unsigned long long)startms);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write (context->out->fh, subline, length);
wrote_something=1;
if (i!=14)
write (context->out->fh, encoded_br, encoded_br_length);
write (context->out->fh,encoded_crlf, encoded_crlf_length);
}
}
sprintf ((char *) str,"</P></SYNC>\r\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
sprintf ((char *) str,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
(unsigned long long)endms);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used = encode_line(context->buffer,(unsigned char *) str);
write (context->out->fh, context->buffer, used);
return wrote_something;
}

225
src/lib_ccx/608_smptett.c Normal file
View File

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

View File

@@ -116,7 +116,7 @@ spupng_write_png(struct spupng_t *sp, struct eia608_screen* data,
return 1;
}
int
int
spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
{
png_structp png_ptr;
@@ -124,7 +124,7 @@ spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
png_bytep *row_pointer;
png_bytep image;
int ww, wh, rowstride, row_adv;
int row;
int row;
assert ((sizeof(png_byte) == sizeof(uint8_t))
&& (sizeof(*image) == sizeof(uint8_t)));
@@ -194,9 +194,9 @@ unknown_error:
int
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
struct s_context_cc608 *context)
struct encoder_ctx *context)
{
LLONG ms_start = context->current_visible_start_ms + subs_delay;
LLONG ms_start = data->start_time + context->subs_delay;
if (ms_start < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
@@ -220,17 +220,17 @@ spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
return 0;
}
LLONG ms_end = get_visible_end() + subs_delay;
LLONG ms_end = data->end_time;
sprintf(sp->pngfile, "%s/sub%04d.png", sp->dirname, sp->fileIndex++);
if ((sp->fppng = fopen(sp->pngfile, "wb")) == NULL)
{
fatal(EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot open %s: %s\n",
sp->pngfile, strerror(errno));
}
if (!spupng_export_png(sp, data))
{
fatal(EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Cannot write %s: %s\n",
sp->pngfile, strerror(errno));
}
fclose(sp->fppng);
@@ -259,15 +259,15 @@ spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
break;
}
}
strncat(str,(const char*)subline,256);
strncat(str,"\n",256);
strncat(str,(const char*)subline,256);
strncat(str,"\n",256);
}
}
write_spucomment(sp,str);
return 1;
}
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context)
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context)
{
if (0 != context->out->spupng_data)
{
@@ -276,4 +276,3 @@ int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608
}
return 0;
}

View File

@@ -1,9 +1,9 @@
#ifndef __608_SPUPNG_H__
#include "ccextractor.h"
#include "lib_ccx.h"
#include "spupng_encoder.h"
#include "ccx_encoders_common.h"
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct s_context_cc608 *context);
int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *context);
#endif /* __608_SPUPNG_H__ */

262
src/lib_ccx/608_srt.c Normal file
View File

@@ -0,0 +1,262 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.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 */
void 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;
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);
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);
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption - - -\n");
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
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_srt() - not enough memory.\n");
int pos_r=0;
int pos_w=0;
// Scan for \n in the string and replace it with a 0
while (pos_r<len)
{
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
{
unescaped[pos_w]=0;
pos_r+=2;
}
else
{
unescaped[pos_w]=string[pos_r];
pos_r++;
}
pos_w++;
}
unescaped[pos_w]=0;
// Now read the unescaped string (now several string'z and write them)
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
unsigned int u = encode_line (el, begin);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write(context->out->fh, el, u);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
begin+= strlen ((const char *) begin)+1;
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
write(context->out->fh, encoded_crlf, encoded_crlf_length);
free(el);
free(unescaped);
}
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
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
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start;
ms_end = sub->start_time;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time;
ms_end = sub->end_time;
}
else if (context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = 1;
ms_end = sub->start_time;
}
if(sub->nb_data == 0 )
return 0;
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))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
mstotime (ms_start,&h1,&m1,&s1,&ms1);
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);
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);
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);
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
return ret;
}
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context)
{
int used;
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
LLONG ms_start, ms_end;
int wrote_something = 0;
ms_start = data->start_time;
int prev_line_start=-1, prev_line_end=-1; // Column in which the previous line started and ended, for autodash
int prev_line_center1=-1, prev_line_center2=-1; // Center column of previous line text
int empty_buf=1;
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
empty_buf=0;
break;
}
}
if (empty_buf) // Prevent writing empty screens. Not needed in .srt
return 0;
ms_start+=context->subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return 0;
ms_end = data->end_time;
mstotime (ms_start,&h1,&m1,&s1,&ms1);
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
char timeline[128];
context->srt_counter++;
sprintf(timeline, "%u%s", context->srt_counter, encoded_crlf);
used = encode_line(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);
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
write (context->out->fh, context->buffer, used);
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
if (ccx_options.sentence_cap)
{
capitalize (i,data);
correct_case(i,data);
}
if (ccx_options.autodash && ccx_options.trim_subs)
{
int first=0, last=31, center1=-1, center2=-1;
unsigned char *line = data->characters[i];
int do_dash=1, colon_pos=-1;
find_limit_characters(line,&first,&last);
if (first==-1 || last==-1) // Probably a bug somewhere though
break;
// Is there a speaker named, for example: TOM: What are you doing?
for (int j=first;j<=last;j++)
{
if (line[j]==':')
{
colon_pos=j;
break;
}
if (!isupper (line[j]))
break;
}
if (prev_line_start==-1)
do_dash=0;
if (first==prev_line_start) // Case of left alignment
do_dash=0;
if (last==prev_line_end) // Right align
do_dash=0;
if (first>prev_line_start && last<prev_line_end) // Fully contained
do_dash=0;
if ((first>prev_line_start && first<prev_line_end) || // Overlap
(last>prev_line_start && last<prev_line_end))
do_dash=0;
center1=(first+last)/2;
if (colon_pos!=-1)
{
while (colon_pos<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)
write(context->out->fh, "- ", 2);
prev_line_start=first;
prev_line_end=last;
prev_line_center1=center1;
prev_line_center2=center2;
}
int length = get_decoder_line_encoded (subline, i, data);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
write(context->out->fh, subline, length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
wrote_something=1;
// fprintf (wb->fh,encoded_crlf);
}
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
// fprintf (wb->fh, encoded_crlf);
write (context->out->fh, encoded_crlf, encoded_crlf_length);
return wrote_something;
}

View File

@@ -4,10 +4,10 @@ EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE)
00-1F -> Characters that are in the G2 group in 20-3F,
except for 06, which is used for the closed captions
sign "CC" which is defined in group G3 as 00. (this
sign "CC" which is defined in group G3 as 00. (this
is by the article 33).
20-7F -> Group G0 as is - corresponds to the ASCII code
80-9F -> Characters that are in the G2 group in 60-7F
20-7F -> Group G0 as is - corresponds to the ASCII code
80-9F -> Characters that are in the G2 group in 60-7F
(there are several blank characters here, that's OK)
A0-FF -> Group G1 as is - non-English characters and symbols
*/
@@ -31,7 +31,7 @@ unsigned char get_internal_from_G2 (unsigned char g2_char)
if (g2_char>=0x60 && g2_char<=0x7F)
return g2_char+0x20;
// Rest unmapped, so we return a blank space
return 0x20;
return 0x20;
}
// TODO: Probably not right
@@ -39,7 +39,7 @@ unsigned char get_internal_from_G2 (unsigned char g2_char)
unsigned char get_internal_from_G3 (unsigned char g3_char)
{
if (g3_char==0xa0) // The "CC" (closed captions) sign
return 0x06;
return 0x06;
// Rest unmapped, so we return a blank space
return 0x20;
return 0x20;
}

View File

@@ -0,0 +1,27 @@
cmake_policy(SET CMP0037 NEW)
SET (CMAKE_C_FLAGS "-O0 -Wall -g -std=gnu99")
if (WITH_FFMPEG)
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
endif (WITH_FFMPEG)
AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
#AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
add_library(ccx ${SOURCEFILE})
FILE(GLOB HeaderFiles *.h)
file(WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n"
"includedir=\${prefix}/include\n"
"libdir=\${prefix}/lib\n\n"
"Name: ccx\n"
"Description: Closed Caption Extraction library\n"
"Version: 0.75\n"
"Cflags: -I\${includedir}/\n"
"Libs: -L\${libdir} -lccx -lpng\n"
"Libs.private: -lpng\n" )
install (TARGETS ccx DESTINATION lib)
install (FILES ${HeaderFiles} DESTINATION include)
install (FILES ccx.pc DESTINATION lib/pkgconfig )

View File

@@ -1,7 +1,8 @@
/* This file contains functions that report the user of the GUI of
relevant events. */
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
static int credits_shown=0;
unsigned long net_activity_gui=0;
@@ -29,71 +30,59 @@ void activity_input_file_open (const char *filename)
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
fflush (stderr);
fflush (stderr);
}
}
void activity_xds_program_identification_number (unsigned minutes, unsigned hours, unsigned date, unsigned month)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###XDSPROGRAMIDENTIFICATIONNUMBER#%u#%u#%u#%u\n", minutes,hours,date,month);
fflush (stderr);
}
void activity_library_process(enum ccx_common_logging_gui message_type, ...){
if (ccx_options.gui_mode_reports){
va_list args;
va_start(args, message_type);
switch (message_type)
{
case CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS:
vfprintf(stderr, "###XDSNETWORKCALLLETTERS#%s\n",args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION:
vfprintf(stderr, "###XDSPROGRAMDESC#%d#%s\n", args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR:
vfprintf(stderr, "###XDSPROGRAMIDENTIFICATIONNUMBER#%u#%u#%u#%u\n", args);
break;
case CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME:
vfprintf(stderr, "###XDSPROGRAMNAME#%s\n", args);
break;
default:
break;
}
fflush(stderr);
va_end(args);
}
}
void activity_xds_network_call_letters (const char *program_name)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###XDSNETWORKCALLLETTERS#%s\n", program_name);
fflush (stderr);
}
}
void activity_xds_program_name (const char *program_name)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###XDSPROGRAMNAME#%s\n", program_name);
fflush (stderr);
}
}
void activity_xds_program_description (int line_num, const char *program_desc)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###XDSPROGRAMDESC#%d#%s\n", line_num, program_desc);
fflush (stderr);
}
}
void activity_video_info (int hor_size,int vert_size,
void activity_video_info (int hor_size,int vert_size,
const char *aspect_ratio, const char *framerate)
{
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###VIDEOINFO#%u#%u#%s#%s\n",
hor_size,vert_size, aspect_ratio, framerate);
fflush (stderr);
fflush (stderr);
}
}
void activity_message (const char *fmt, ...)
{
if (ccx_options.gui_mode_reports)
{
va_list args;
va_list args;
fprintf (stderr, "###MESSAGE#");
va_start(args, fmt);
fprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
fflush (stderr);
fflush (stderr);
}
}
@@ -102,7 +91,7 @@ void activity_input_file_closed (void)
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILECLOSED\n");
fflush (stderr);
fflush (stderr);
}
}
@@ -111,7 +100,7 @@ void activity_program_number (unsigned program_number)
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###TSPROGRAMNUMBER#%u\n",program_number);
fflush (stderr);
fflush (stderr);
}
}
@@ -141,7 +130,6 @@ void activity_header (void)
credits_shown=1;
mprint ("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION);
mprint ("Teletext portions taken from Petr Kutalek's telxcc\n");
mprint ("--------------------------------------------------------------------------\n");
mprint ("--------------------------------------------------------------------------\n");
}
}

View File

@@ -1,4 +1,5 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "asf_constants.h"
// Indicate first / subsequent calls to asf_getmoredata()
@@ -28,7 +29,7 @@ uint32_t asf_readval(void *val, int ltype)
rval = *((uint32_t*)val);
break;
default:
fatal (EXIT_BUG_BUG, "Wrong type ...\n");
fatal (CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
break;
}
return rval;
@@ -36,7 +37,7 @@ uint32_t asf_readval(void *val, int ltype)
char *guidstr(void *val)
{
static char sbuf[32];
static char sbuf[40];
sprintf(sbuf,"%08lX-%04X-%04X-",
(long)*((uint32_t*)((char*)val+0)),
@@ -60,7 +61,7 @@ asf_data asf_data_container;
* 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(void)
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
{
int enough = 0;
int payload_read = 0;
@@ -81,14 +82,14 @@ LLONG asf_getmoredata(void)
// Data Object Loop
int datapacketlength = 0; // Collect the read header bytes
// Payload parsing information
// Payload parsing information
int SequenceType = 0; // ASF
int PaddingLType = 0; // ASF
uint32_t Sequence = 0;
int PaddingLType = 0; // ASF
uint32_t Sequence = 0;
uint32_t SendTime = 0;
int payloadparsersize = 0; // Infered (PacketLType + SequenceType + PaddingLType + 6);
uint32_t OffsetMediaLength = 0; // ASF
uint32_t ReplicatedLength = 0; // ASF
@@ -140,7 +141,7 @@ LLONG asf_getmoredata(void)
.StreamNumberLType = 0,
.PacketLength = 0,
.PaddingLength = 0
};
};
// Initialize the Payload Extension System
for(int stream=0; stream<STREAMNUM; stream++)
{
@@ -151,8 +152,8 @@ LLONG asf_getmoredata(void)
asf_data_container.PayloadExtPTSEntry[stream] = -1;
}
buffered_read(asf_data_container.parsebuf,30);
past+=result;
buffered_read(ctx, asf_data_container.parsebuf,30);
ctx->past+=result;
if (result!=30)
{
mprint("Premature end of file!\n");
@@ -173,7 +174,7 @@ LLONG asf_getmoredata(void)
dbg_print(CCX_DMT_PARSE, "Length: %lld\n", asf_data_container.HeaderObjectSize);
dbg_print(CCX_DMT_PARSE,"\nNumber of header objects: %ld\n",
(long)*((uint32_t*)(asf_data_container.parsebuf + 24)));
if (asf_data_container.HeaderObjectSize > asf_data_container.parsebufsize) {
asf_data_container.parsebuf = (unsigned char*)realloc(asf_data_container.parsebuf, (size_t)asf_data_container.HeaderObjectSize);
@@ -185,8 +186,8 @@ LLONG asf_getmoredata(void)
curpos = asf_data_container.parsebuf + 30;
getbytes = asf_data_container.HeaderObjectSize - 30;
buffered_read(curpos, (int) getbytes);
past+=result;
buffered_read(ctx, curpos, (int) getbytes);
ctx->past+=result;
if (result!=getbytes)
{
mprint("Premature end of file!\n");
@@ -202,7 +203,7 @@ LLONG asf_getmoredata(void)
if( !memcmp(curpos, ASF_FILE_PROPERTIES, 16 ) )
{
// Mandatory Object, only one.
// Mandatory Object, only one.
dbg_print(CCX_DMT_PARSE, "\nFile Properties Object (size: %lld)\n", hpobjectsize);
asf_data_container.FileSize = *((int64_t*)(curpos + 40));
@@ -211,11 +212,11 @@ LLONG asf_getmoredata(void)
SeekableFlag = 0x2 & curpos[88];
MinPacketSize = *((uint32_t*)(curpos+92));
MaxPacketSize = *((uint32_t*)(curpos+96));
dbg_print(CCX_DMT_PARSE, "FileSize: %lld Packet count: %lld\n", asf_data_container.FileSize, DataPacketsCount);
dbg_print(CCX_DMT_PARSE, "Broadcast: %d - Seekable: %d\n", BroadcastFlag, SeekableFlag);
dbg_print(CCX_DMT_PARSE, "MiDPS: %d MaDPS: %d\n", MinPacketSize, MaxPacketSize);
}
else if( !memcmp(curpos,ASF_STREAM_PROPERTIES, 16 ) )
{
@@ -225,7 +226,7 @@ LLONG asf_getmoredata(void)
asf_data_container.StreamProperties.VideoStreamNumber = *(curpos + 72) & 0x7F;
dbg_print(CCX_DMT_PARSE, "Stream Type: ASF_Video_Media\n");
dbg_print(CCX_DMT_PARSE, "Video Stream Number: %d\n", asf_data_container.StreamProperties.VideoStreamNumber);
}
else if( !memcmp(curpos+24, ASF_AUDIO_MEDIA, 16 ) )
{
@@ -237,7 +238,7 @@ LLONG asf_getmoredata(void)
{
dbg_print(CCX_DMT_PARSE, "Stream Type: %s\n",
guidstr(curpos+24));
dbg_print(CCX_DMT_PARSE, "Stream Number: %d\n", *(curpos+72) & 0x7F );
dbg_print(CCX_DMT_PARSE, "Stream Number: %d\n", *(curpos+72) & 0x7F );
}
}
else if( !memcmp(curpos,ASF_HEADER_EXTENSION, 16 ) )
@@ -273,7 +274,7 @@ LLONG asf_getmoredata(void)
StreamNumber, StreamNameCount, PayloadExtensionSystemCount);
if ( StreamNumber >= STREAMNUM )
fatal(EXIT_BUG_BUG, "STREAMNUM too small. Send bug report!/n");
fatal(CCX_COMMON_EXIT_BUG_BUG, "STREAMNUM too small. Send bug report!/n");
for(int i=0; i<StreamNameCount; i++)
{
@@ -285,7 +286,7 @@ LLONG asf_getmoredata(void)
int extensionsysteminfolength;
if ( PayloadExtensionSystemCount > PAYEXTNUM )
fatal(EXIT_BUG_BUG, "PAYEXTNUM too small. Send bug report!/n");
fatal(CCX_COMMON_EXIT_BUG_BUG, "PAYEXTNUM too small. Send bug report!/n");
for(int i=0; i<PayloadExtensionSystemCount; i++)
{
@@ -439,7 +440,7 @@ LLONG asf_getmoredata(void)
dbg_print(CCX_DMT_PARSE, "%02X:",*((unsigned char*)(edescval+ii)));
}
if (DescriptorValueLength>8)
dbg_print(CCX_DMT_PARSE, "skipped %d more",DescriptorValueLength-8);
dbg_print(CCX_DMT_PARSE, "skipped %d more",DescriptorValueLength-8);
dbg_print(CCX_DMT_PARSE, " (BYTES)\n");
break;
case 2: // BOOL
@@ -455,10 +456,10 @@ LLONG asf_getmoredata(void)
dbg_print(CCX_DMT_PARSE, "%u (WORD)\n",(int)*((uint16_t*)edescval));
break;
default:
fatal(EXIT_BUG_BUG, "Wrong type ...\n");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
break;
}
if(!memcmp(econtentpos+2, L"WM/VideoClosedCaptioning"
,DescriptorNameLength))
{
@@ -534,8 +535,8 @@ LLONG asf_getmoredata(void)
asf_data_container.PacketSize = MinPacketSize;
// Now the Data Object, except for the packages
buffered_read(asf_data_container.parsebuf, 50); // No realloc needed.
past+=result;
buffered_read(ctx, asf_data_container.parsebuf, 50); // No realloc needed.
ctx->past+=result;
if (result!=50)
{
mprint("Premature end of file!\n");
@@ -557,7 +558,7 @@ LLONG asf_getmoredata(void)
asf_data_container.TotalDataPackets = *((uint32_t*)(asf_data_container.parsebuf + 40));
dbg_print(CCX_DMT_PARSE, "Size: %lld\n", asf_data_container.DataObjectSize);
dbg_print(CCX_DMT_PARSE, "Number of data packets: %ld\n", (long)asf_data_container.TotalDataPackets);
reentry = 0; // Make sure we read the Data Packet Headers
} // End of if (firstcall)
@@ -576,8 +577,8 @@ LLONG asf_getmoredata(void)
dbg_print(CCX_DMT_PARSE, "\nReading packet %d/%d\n", asf_data_container.datapacketcur + 1, asf_data_container.TotalDataPackets);
// First packet
buffered_read(asf_data_container.parsebuf, 1); // No realloc needed.
past+=result;
buffered_read(ctx, asf_data_container.parsebuf, 1); // No realloc needed.
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=1)
{
@@ -593,8 +594,8 @@ LLONG asf_getmoredata(void)
{
fatal(EXIT_NOT_CLASSIFIED, "Error Correction Length Type not 00 - reserved - aborting ...\n");
}
buffered_read(asf_data_container.parsebuf + 1, ecdatalength);
past+=result;
buffered_read(ctx, asf_data_container.parsebuf + 1, ecdatalength);
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=ecdatalength)
{
@@ -614,8 +615,8 @@ LLONG asf_getmoredata(void)
}
// Now payload parsing information
buffered_read(asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
past+=result;
buffered_read(ctx, asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=2)
{
@@ -650,8 +651,8 @@ LLONG asf_getmoredata(void)
payloadparsersize = asf_data_container.PacketLType + SequenceType + PaddingLType + 6;
buffered_read(asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
past+=result;
buffered_read(ctx, asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=payloadparsersize)
{
@@ -688,8 +689,8 @@ LLONG asf_getmoredata(void)
{
unsigned char plheader[1];
buffered_read(plheader, 1);
past+=result;
buffered_read(ctx, plheader, 1);
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=1)
{
@@ -726,9 +727,9 @@ LLONG asf_getmoredata(void)
dbg_print(CCX_DMT_PARSE, "\nMultiple payloads %d/%d\n", asf_data_container.payloadcur + 1, asf_data_container.NumberOfPayloads);
int payloadheadersize = 1 + asf_data_container.MediaNumberLType + asf_data_container.OffsetMediaLType + asf_data_container.ReplicatedLType;
buffered_read(asf_data_container.parsebuf, payloadheadersize); // No realloc needed
past+=result;
buffered_read(ctx, asf_data_container.parsebuf, payloadheadersize); // No realloc needed
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=payloadheadersize)
{
@@ -737,7 +738,7 @@ LLONG asf_getmoredata(void)
return payload_read;
}
datapacketlength+=payloadheadersize;
asf_data_container.PayloadStreamNumber = *asf_data_container.parsebuf & 0x7F;
asf_data_container.KeyFrame = (*asf_data_container.parsebuf & 0x80) && 1;
@@ -755,8 +756,8 @@ LLONG asf_getmoredata(void)
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
asf_data_container.parsebufsize = ReplicatedLength;
}
buffered_read(asf_data_container.parsebuf, (long)ReplicatedLength);
past+=result;
buffered_read(ctx, asf_data_container.parsebuf, (long)ReplicatedLength);
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result!=ReplicatedLength)
{
@@ -804,7 +805,7 @@ LLONG asf_getmoredata(void)
// unknown = *((uint32_t*)(reppos+4));
rtStart = *((int64_t*)(reppos+8));
rtEnd = *((int64_t*)(reppos+16));
//printf("dwVersion: %d unknown: 0x%04X\n", dwVersion, unknown);
}
@@ -823,7 +824,7 @@ LLONG asf_getmoredata(void)
print_mstime(PresentationTimems));
dbg_print(CCX_DMT_PARSE," dvr-ms PTS: %s+%lld\n",
print_mstime(rtStart/10000), (rtEnd-rtStart)/10000);
datapacketlength+=ReplicatedLength;
// Only multiple payload packages have this value
@@ -831,8 +832,8 @@ LLONG asf_getmoredata(void)
{
unsigned char plheader[4];
buffered_read(plheader, asf_data_container.PayloadLType);
past+=result;
buffered_read(ctx, plheader, asf_data_container.PayloadLType);
ctx->past+=result;
asf_data_container.dobjectread += result;
if (result != asf_data_container.PayloadLType)
{
@@ -918,9 +919,9 @@ LLONG asf_getmoredata(void)
// a jump this needs synchronizing, otherwise it was
// just a gap in the captions.
if (!asf_data_container.StreamProperties.VideoJump)
CaptionGap = 1;
ccx_common_timing_settings.disable_sync_check = 1;
else
CaptionGap = 0;
ccx_common_timing_settings.disable_sync_check = 0;
}
asf_data_container.StreamProperties.VideoJump = 0;
}
@@ -955,7 +956,7 @@ LLONG asf_getmoredata(void)
dbg_print(CCX_DMT_PARSE, "\nVideo stream object");
dbg_print(CCX_DMT_PARSE, " read with PTS: %s\n",
print_mstime(asf_data_container.StreamProperties.currDecodeStreamPTS));
// Enough for now
enough = 1;
@@ -973,11 +974,11 @@ LLONG asf_getmoredata(void)
int want = (long)((BUFSIZE - inbuf)>asf_data_container.PayloadLength ?
asf_data_container.PayloadLength : (BUFSIZE - inbuf));
if (want < (long)asf_data_container.PayloadLength)
fatal(EXIT_BUG_BUG, "Buffer size to small for ASF payload!\nPlease file a bug report!\n");
buffered_read (buffer+inbuf,want);
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;
past+=result;
ctx->past+=result;
if (result != asf_data_container.PayloadLength)
{
mprint("Premature end of file!\n");
@@ -990,8 +991,8 @@ LLONG asf_getmoredata(void)
{
// Skip non-cc data
dbg_print(CCX_DMT_PARSE, "Skipping Stream #%d data ...\n", asf_data_container.PayloadStreamNumber);
buffered_skip((int)asf_data_container.PayloadLength);
past+=result;
buffered_skip(ctx, (int)asf_data_container.PayloadLength);
ctx->past+=result;
if (result != asf_data_container.PayloadLength)
{
mprint("Premature end of file!\n");
@@ -1000,7 +1001,7 @@ LLONG asf_getmoredata(void)
}
asf_data_container.dobjectread += result;
}
asf_data_container.payloadcur++;
}
if (enough)
@@ -1008,8 +1009,8 @@ LLONG asf_getmoredata(void)
// Skip padding bytes
dbg_print(CCX_DMT_PARSE, "Skip %d padding\n", asf_data_container.PaddingLength);
buffered_skip((long)asf_data_container.PaddingLength);
past+=result;
buffered_skip(ctx, (long)asf_data_container.PaddingLength);
ctx->past+=result;
if (result != asf_data_container.PaddingLength)
{
mprint("Premature end of file!\n");
@@ -1028,8 +1029,8 @@ LLONG asf_getmoredata(void)
// 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((int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
past+=result;
buffered_skip(ctx, (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
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;

View File

@@ -1,7 +1,9 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "utility.h"
#include <math.h>
// Functions to parse a AVC/H.264 data stream, see ISO/IEC 14496-10
// 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;
@@ -12,7 +14,7 @@ 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 (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type);
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
@@ -44,15 +46,15 @@ void init_avc(void)
cc_data = (unsigned char*)malloc(1024);
}
void do_NAL (unsigned char *NALstart, LLONG NAL_length)
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
{
unsigned char *NALstop;
unsigned nal_unit_type = *NALstart & 0x1F;
NALstop = NAL_length+NALstart;
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
if (NALstop==NULL) // remove_03emu failed.
if (NALstop==NULL) // remove_03emu failed.
{
mprint ("\rNotice: NAL of type %u had to be skipped because remove_03emu failed.\n", nal_unit_type);
return;
@@ -66,22 +68,22 @@ void do_NAL (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++;
num_nal_unit_type_7++;
seq_parameter_set_rbsp(NALstart+1, NALstop);
got_seq_para = 1;
}
else if ( got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
else if ( 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
// Found coded slice of a non-IDR picture
// We only need the slice header data, no need to implement
// slice_layer_without_partitioning_rbsp( );
slice_header(NALstart+1, NALstop, nal_unit_type);
slice_header(ctx, NALstart+1, NALstop, nal_unit_type, sub);
}
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
{
// Found SEI (used for subtitles)
//set_fts(); // FIXME - check this!!!
//set_fts(); // FIXME - check this!!!
sei_rbsp(NALstart+1, NALstop);
}
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_PICTURE_PARAMETER_SET )
@@ -99,7 +101,7 @@ void do_NAL (unsigned char *NALstart, LLONG NAL_length)
// Process inbuf bytes in buffer holding and AVC (H.264) video stream.
// The number of processed bytes is returned.
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
{
unsigned char *bpos = avcbuf;
unsigned char *NALstart;
@@ -108,16 +110,16 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
// At least 5 bytes are needed for a NAL unit
if(avcbuflen <= 5)
{
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"NAL unit need at last 5 bytes ...");
}
}
// Warning there should be only leading zeros, nothing else
// Warning there should be only leading zeros, nothing else
if( !(bpos[0]==0x00 && bpos[1]==0x00) )
{
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Broken AVC stream - no 0x0000 ...");
}
}
bpos = bpos+2;
int firstloop=1; // Check for valid start code at buffer start
@@ -138,7 +140,7 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
else if(firstloop && *bpos != 0x00)
{
// Not 0x00 or 0x01
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Broken AVC stream - no 0x00 ...");
}
bpos++;
@@ -193,7 +195,7 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
if(*NALstart & 0x80)
{
dump(CCX_DMT_GENERIC_NOTICES, NALstart-4,10, 0, 0);
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Broken AVC stream - forbidden_zero_bit not zero ...");
}
@@ -202,17 +204,17 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen)
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);
do_NAL (NALstart, NALstop-NALstart);
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;
}
#define ZEROBYTES_SHORTSTARTCODE 2
#define ZEROBYTES_SHORTSTARTCODE 2
// Copied for reference decoder, see if it behaves different that Volker's code
int EBSPtoRBSP(unsigned char *streamBuffer, int end_bytepos, int begin_bytepos)
@@ -227,9 +229,9 @@ int EBSPtoRBSP(unsigned char *streamBuffer, int end_bytepos, int begin_bytepos)
for(i = begin_bytepos; i < end_bytepos; ++i)
{ //starting from begin_bytepos to avoid header information
//in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position
if(count == ZEROBYTES_SHORTSTARTCODE && streamBuffer[i] < 0x03)
return -1;
//in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position
if(count == ZEROBYTES_SHORTSTARTCODE && streamBuffer[i] < 0x03)
return -1;
if(count == ZEROBYTES_SHORTSTARTCODE && streamBuffer[i] == 0x03)
{
//check the 4th byte after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003
@@ -260,8 +262,8 @@ typedef unsigned int u32;
u32 avc_remove_emulation_bytes(const unsigned char *buffer_src, unsigned char *buffer_dst, u32 nal_size) ;
unsigned char *remove_03emu(unsigned char *from, unsigned char *to)
{
int num=to-from;
{
int num=to-from;
int newsize = EBSPtoRBSP (from,num,0); //TODO: Do something if newsize == -1 (broken NAL)
if (newsize==-1)
return NULL;
@@ -282,7 +284,7 @@ void sei_rbsp (unsigned char *seibuf, unsigned char *seiend)
{
if(*tbuf != 0x80)
mprint("Strange rbsp_trailing_bits value: %02X\n",*tbuf);
}
}
else
{
// TODO: This really really looks bad
@@ -305,33 +307,33 @@ unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend)
payloadType+=255;
seibuf++;
}
payloadType += *seibuf;
payloadType += *seibuf;
seibuf++;
int payloadSize = 0;
while (*seibuf==0xff)
{
payloadSize+=255;
seibuf++;
}
payloadSize += *seibuf;
payloadSize += *seibuf;
seibuf++;
int broken=0;
unsigned char *paystart = seibuf;
seibuf+=payloadSize;
dvprint("Payload type: %d size: %d - ", payloadType, payloadSize);
if(seibuf > seiend )
if(seibuf > seiend )
{
// TODO: What do we do here?
broken=1;
if (payloadType==4)
if (payloadType==4)
{
dbg_print(CCX_DMT_VERBOSE, "Warning: Subtitles payload seems incorrect (too long), continuing but it doesn't look good..");
}
else
else
{
dbg_print(CCX_DMT_VERBOSE, "Warning: Non-subtitles payload seems incorrect (too long), continuing but it doesn't look good..");
}
@@ -352,7 +354,7 @@ void copy_ccdata_to_buffer (char *source, int new_cc_count)
mprint ("Warning: Probably loss of CC data, unsaved buffer being rewritten\n");
ccblocks_in_avc_lost++;
}
memcpy(cc_data+cc_count*3, source, new_cc_count*3+1);
memcpy(cc_data+cc_count*3, source, new_cc_count*3+1);
cc_count+=new_cc_count;
cc_buffer_saved=0;
}
@@ -393,7 +395,7 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
}
switch (itu_t_35_provider_code)
{
{
case 0x0031: // ANSI/SCTE 128
dbg_print(CCX_DMT_VERBOSE, "Caption block in ANSI/SCTE 128...");
if (*tbuf==0x47 && *(tbuf+1)==0x41 && *(tbuf+2)==0x39 && *(tbuf+3)==0x34) // ATSC1_data() - GA94
@@ -419,14 +421,14 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
*/
local_cc_count= *tbuf & 0x1F;
process_cc_data_flag = (*tbuf & 0x40) >> 6;
/* if (!process_cc_data_flag)
{
mprint ("process_cc_data_flag == 0, skipping this caption block.\n");
break;
} */
/*
The following tests are not passed in Comcast's sample videos. *tbuf here is always 0x41.
The following tests are not passed in Comcast's sample videos. *tbuf here is always 0x41.
if (! (*tbuf & 0x80)) // First bit must be 1
{
printf ("Fixed bit should be 1, but it's 0 - skipping this caption block.\n");
@@ -450,15 +452,15 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
/* TODO: I don't think we have user_data_len here
if (cc_count*3+3 != user_data_len)
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Syntax problem: user_data_len != cc_count*3+3."); */
// Enough room for CC captions?
if (cc_tmpdata+local_cc_count*3 >= userend)
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Syntax problem: Too many caption blocks.");
if (cc_tmpdata[local_cc_count*3]!=0xFF)
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Syntax problem: Final 0xFF marker missing.");
// Save the data and process once we know the sequence number
@@ -478,19 +480,19 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
default:
dbg_print(CCX_DMT_VERBOSE, "SCTE/ATSC reserved.\n");
}
}
else if (*tbuf==0x44 && *(tbuf+1)==0x54 && *(tbuf+2)==0x47 && *(tbuf+3)==0x31) // afd_data() - DTG1
{
;
// Active Format Description Data. Actually unrelated to captions. Left
// here in case we want to do some reporting eventually. From specs:
// "Active Format Description (AFD) should be included in video user
// data whenever the rectangular picture area containing useful
// "Active Format Description (AFD) should be included in video user
// data whenever the rectangular picture area containing useful
// information does not extend to the full height or width of the coded
// frame. AFD data may also be included in user data when the
// frame. AFD data may also be included in user data when the
// rectangular picture area containing
// useful information extends to the fullheight and width of the
// useful information extends to the fullheight and width of the
// coded frame."
}
else
@@ -505,7 +507,7 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
if(user_data_type_code != 0x03)
{
dbg_print(CCX_DMT_VERBOSE, "Not supported user_data_type_code: %02x\n",
user_data_type_code);
user_data_type_code);
return;
}
tbuf++;
@@ -522,15 +524,15 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
cc_tmpdata = tbuf+2;
if (local_cc_count*3+3 != user_data_len)
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Syntax problem: user_data_len != cc_count*3+3.");
// Enough room for CC captions?
if (cc_tmpdata+local_cc_count*3 >= userend)
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Syntax problem: Too many caption blocks.");
if (cc_tmpdata[local_cc_count*3]!=0xFF)
fatal(EXIT_BUG_BUG,
fatal(CCX_COMMON_EXIT_BUG_BUG,
"Syntax problem: Final 0xFF marker missing.");
// Save the data and process once we know the sequence number
@@ -563,178 +565,250 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
dvprint("SEQUENCE PARAMETER SET (bitlen: %lld)\n", q1.bitsleft);
tmp=u(&q1,8);
dvprint("profile_idc= %llX\n", tmp);
LLONG profile_idc = tmp;
dvprint("profile_idc= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("constraint_set0_flag= %llX\n", tmp);
dvprint("constraint_set0_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("constraint_set1_flag= %llX\n", tmp);
dvprint("constraint_set1_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("constraint_set2_flag= %llX\n", tmp);
tmp=u(&q1,5);
dvprint("reserved= %llX\n", tmp);
dvprint("constraint_set2_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp = u(&q1, 1);
dvprint("constraint_set3_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp = u(&q1, 1);
dvprint("constraint_set4_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp = u(&q1, 1);
dvprint("constraint_set5_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,2);
dvprint("reserved= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,8);
dvprint("level_idc= %llX\n", tmp);
dvprint("level_idc= % 4lld (%#llX)\n",tmp,tmp);
seq_parameter_set_id = ue(&q1);
dvprint("seq_parameter_set_id= %llX\n", seq_parameter_set_id);
log2_max_frame_num = (int)ue(&q1)+4;
dvprint("log2_max_frame_num4= %X\n", log2_max_frame_num);
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", seq_parameter_set_id,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){
LLONG chroma_format_idc = ue(&q1);
dvprint("chroma_format_idc= % 4lld (%#llX)\n", chroma_format_idc,chroma_format_idc);
if (chroma_format_idc == 3){
tmp = u(&q1, 1);
dvprint("separate_colour_plane_flag= % 4lld (%#llX)\n", tmp, tmp);
}
tmp = ue(&q1);
dvprint("bit_depth_luma_minus8= % 4lld (%#llX)\n", tmp, tmp);
tmp = ue(&q1);
dvprint("bit_depth_chroma_minus8= % 4lld (%#llX)\n", tmp, tmp);
tmp = u(&q1,1);
dvprint("qpprime_y_zero_transform_bypass_flag= % 4lld (%#llX)\n", tmp, tmp);
tmp = u(&q1, 1);
dvprint("seq_scaling_matrix_present_flag= % 4lld (%#llX)\n", tmp, tmp);
if (tmp == 1){
// WVI: untested, just copied from specs.
for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++){
tmp = u(&q1, 1);
dvprint("seq_scaling_list_present_flag[%d]= % 4lld (%#llX)\n",i,tmp, tmp);
if (tmp){
// We use a "dummy"/slimmed-down replacement here. Actual/full code can be found in the spec (ISO/IEC 14496-10:2012(E)) chapter 7.3.2.1.1.1 - Scaling list syntax
if (i < 6){
// Scaling list size 16
// TODO: replace with full scaling list implementation?
int nextScale = 8;
int lastScale = 8;
for (int j = 0; j < 16; j++){
if (nextScale != 0){
int64_t delta_scale = se(&q1);
nextScale = (lastScale + delta_scale + 256) % 256;
}
lastScale = (nextScale == 0) ? lastScale : nextScale;
}
// END of TODO
}
else {
// Scaling list size 64
// TODO: replace with full scaling list implementation?
int nextScale = 8;
int lastScale = 8;
for (int j = 0; j < 64; j++){
if (nextScale != 0){
int64_t delta_scale = se(&q1);
nextScale = (lastScale + delta_scale + 256) % 256;
}
lastScale = (nextScale == 0) ? lastScale : nextScale;
}
// END of TODO
}
}
}
}
}
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= %X\n", pic_order_cnt_type);
dvprint("pic_order_cnt_type= % 4d (%#X)\n", pic_order_cnt_type,pic_order_cnt_type);
if( pic_order_cnt_type == 0 )
{
log2_max_pic_order_cnt_lsb = (int)ue(&q1)+4;
dvprint("log2_max_pic_order_cnt_lsb= %X\n", log2_max_pic_order_cnt_lsb);
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.
}
else if( pic_order_cnt_type == 1 )
{
// CFS: Untested, just copied from specs.
tmp= u(&q1,1);
dvprint("delta_pic_order_always_zero_flag= %llX\n", tmp);
dvprint("delta_pic_order_always_zero_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp = se(&q1);
dvprint("offset_for_non_ref_pic= %llX\n", tmp);
dvprint("offset_for_non_ref_pic= % 4lld (%#llX)\n",tmp,tmp);
tmp = se(&q1);
dvprint("offset_for_top_to_bottom_field %llX\n", tmp);
dvprint("offset_for_top_to_bottom_field % 4lld (%#llX)\n",tmp,tmp);
LLONG num_ref_frame_in_pic_order_cnt_cycle = ue (&q1);
dvprint("num_ref_frame_in_pic_order_cnt_cycle %llX\n", num_ref_frame_in_pic_order_cnt_cycle);
dvprint("num_ref_frame_in_pic_order_cnt_cycle % 4lld (%#llX)\n", num_ref_frame_in_pic_order_cnt_cycle,num_ref_frame_in_pic_order_cnt_cycle);
for (int i=0; i<num_ref_frame_in_pic_order_cnt_cycle; i++)
{
tmp=se(&q1);
dvprint("offset_for_ref_frame [%d / %d] = %llX\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp);
tmp=se(&q1);
dvprint("offset_for_ref_frame [%d / %d] = % 4lld (%#llX)\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp,tmp);
}
}
else
{
// CFS: Looks like nothing needs to be parsed for pic_order_cnt_type==2 ?
// fatal(EXIT_BUG_BUG, "AVC: pic_order_cnt_type > 1 is not yet supported.");
// Nothing needs to be parsed when pic_order_cnt_type == 2
}
tmp=ue(&q1);
dvprint("num_ref_frames= %llX\n", tmp);
dvprint("max_num_ref_frames= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("gaps allowed= %llX\n", tmp);
dvprint("gaps_in_frame_num_value_allowed_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("pic_width_in_mbs_minus1= %llX\n", tmp);
dvprint("pic_width_in_mbs_minus1= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("pic_height_in_map_units_minus1= %llX\n", tmp);
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= %X\n", frame_mbs_only_flag);
dvprint("frame_mbs_only_flag= % 4d (%#X)\n", frame_mbs_only_flag,frame_mbs_only_flag);
if ( !frame_mbs_only_flag )
{
tmp=u(&q1,1);
dvprint("mb_adaptive_fr_fi_flag= %llX\n", tmp);
dvprint("mb_adaptive_fr_fi_flag= % 4lld (%#llX)\n",tmp,tmp);
}
tmp=u(&q1,1);
dvprint("direct_8x8_inference_f= %llX\n", tmp);
dvprint("direct_8x8_inference_f= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("frame_cropping_flag= %llX\n", tmp);
dvprint("frame_cropping_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=ue(&q1);
dvprint("frame_crop_left_offset= %llX\n", tmp);
dvprint("frame_crop_left_offset= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("frame_crop_right_offset= %llX\n", tmp);
dvprint("frame_crop_right_offset= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("frame_crop_top_offset= %llX\n", tmp);
dvprint("frame_crop_top_offset= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("frame_crop_bottom_offset= %llX\n", tmp);
dvprint("frame_crop_bottom_offset= % 4lld (%#llX)\n",tmp,tmp);
}
tmp=u(&q1,1);
dvprint("vui_parameters_present= %llX\n", tmp);
dvprint("vui_parameters_present= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
dvprint("\nVUI parameters\n");
tmp=u(&q1,1);
dvprint("aspect_ratio_info_pres= %llX\n", tmp);
dvprint("aspect_ratio_info_pres= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=u(&q1,8);
dvprint("aspect_ratio_idc= %llX\n", tmp);
dvprint("aspect_ratio_idc= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp == 255 )
{
tmp=u(&q1,16);
dvprint("sar_width= %llX\n", tmp);
dvprint("sar_width= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,16);
dvprint("sar_height= %llX\n", tmp);
dvprint("sar_height= % 4lld (%#llX)\n",tmp,tmp);
}
}
tmp=u(&q1,1);
dvprint("overscan_info_pres_flag= %llX\n", tmp);
dvprint("overscan_info_pres_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=u(&q1,1);
dvprint("overscan_appropriate_flag= %llX\n", tmp);
dvprint("overscan_appropriate_flag= % 4lld (%#llX)\n",tmp,tmp);
}
tmp=u(&q1,1);
dvprint("video_signal_type_present_flag= %llX\n", tmp);
dvprint("video_signal_type_present_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=u(&q1,3);
dvprint("video_format= %llX\n", tmp);
dvprint("video_format= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("video_full_range_flag= %llX\n", tmp);
dvprint("video_full_range_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("colour_description_present_flag= %llX\n", tmp);
dvprint("colour_description_present_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=u(&q1,8);
dvprint("colour_primaries= %llX\n", tmp);
dvprint("colour_primaries= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,8);
dvprint("transfer_characteristics= %llX\n", tmp);
dvprint("transfer_characteristics= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,8);
dvprint("matrix_coefficients= %llX\n", tmp);
dvprint("matrix_coefficients= % 4lld (%#llX)\n",tmp,tmp);
}
}
tmp=u(&q1,1);
dvprint("chroma_loc_info_present_flag= %llX\n", tmp);
dvprint("chroma_loc_info_present_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=ue(&q1);
dvprint("chroma_sample_loc_type_top_field= %llX\n", tmp);
dvprint("chroma_sample_loc_type_top_field= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
dvprint("chroma_sample_loc_type_bottom_field= %llX\n", tmp);
dvprint("chroma_sample_loc_type_bottom_field= % 4lld (%#llX)\n",tmp,tmp);
}
tmp=u(&q1,1);
dvprint("timing_info_present_flag= %llX\n", tmp);
dvprint("timing_info_present_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
tmp=u(&q1,32);
dvprint("num_units_in_tick= %llX\n", tmp);
LLONG num_units_in_tick = tmp;
dvprint("num_units_in_tick= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,32);
dvprint("time_scale= %llX\n", tmp);
LLONG time_scale = tmp;
dvprint("time_scale= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("fixed_frame_rate_flag= %llX\n", tmp);
int fixed_frame_rate_flag = (int) tmp;
dvprint("fixed_frame_rate_flag= % 4lld (%#llX)\n",tmp,tmp);
// Change: use num_units_in_tick and time_scale to calculate FPS. (ISO/IEC 14496-10:2012(E), page 397 & further)
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);
}
}
tmp=u(&q1,1);
dvprint("nal_hrd_parameters_present_flag= %llX\n", tmp);
dvprint("nal_hrd_parameters_present_flag= % 4lld (%#llX)\n",tmp,tmp);
if ( tmp )
{
dvprint ("nal_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
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++;
return;
}
}
tmp1=u(&q1,1);
dvprint("vcl_hrd_parameters_present_flag= %llX\n", tmp1);
if ( tmp )
{
// TODO.
mprint ("vcl_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
mprint ("vcl_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
num_vcl_hrd++;
// exit(1);
}
}
if ( tmp || tmp1 )
{
tmp=u(&q1,1);
dvprint("low_delay_hrd_flag= %llX\n", tmp);
dvprint("low_delay_hrd_flag= % 4lld (%#llX)\n",tmp,tmp);
return;
}
tmp=u(&q1,1);
dvprint("pic_struct_present_flag= %llX\n", tmp);
dvprint("pic_struct_present_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("bitstream_restriction_flag= %llX\n", tmp);
dvprint("bitstream_restriction_flag= % 4lld (%#llX)\n",tmp,tmp);
// ..
// The hope was to find the GOP length in max_dec_frame_buffering, but
// it was not set in the testfile. Ignore the rest here, it's
@@ -745,7 +819,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
// Process slice header in AVC data.
void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type)
void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
{
LLONG tmp;
struct bitstream q1;
@@ -772,11 +846,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
dvprint("\nSLICE HEADER\n");
tmp=ue(&q1);
dvprint("first_mb_in_slice= %llX\n", tmp);
dvprint("first_mb_in_slice= % 4lld (%#llX)\n",tmp,tmp);
slice_type=ue(&q1);
dvprint("slice_type= %llX\n", slice_type);
tmp=ue(&q1);
dvprint("pic_parameter_set_id= %llX\n", tmp);
dvprint("pic_parameter_set_id= % 4lld (%#llX)\n",tmp,tmp);
lastframe_num = frame_num;
int maxframe_num = (int) ((1<<log2_max_frame_num) - 1);
@@ -808,7 +882,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
if( nal_unit_type == 5 )
{
tmp=ue(&q1);
dvprint("idr_pic_id= %llX\n", tmp);
dvprint("idr_pic_id= % 4lld (%#llX)\n",tmp,tmp);
//TODO
}
if( pic_order_cnt_type == 0 )
@@ -818,7 +892,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
}
if( pic_order_cnt_type == 1 )
{
fatal(EXIT_BUG_BUG, "AVC: pic_order_cnt_type == 1 not yet supported.");
fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type == 1 not yet supported.");
}
#if 0
else
@@ -831,7 +905,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
FrameNumOffset = lastframe_num + maxframe_num;
else
FrameNumOffset = lastframe_num;
LLONG tempPicOrderCnt=0;
if (IdrPicFlag == 1)
tempPicOrderCnt=0;
@@ -851,9 +925,9 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
else
TopFieldOrderCnt = tempPicOrderCnt;
//pic_order_cnt_lsb=tempPicOrderCnt;
//pic_order_cnt_lsb=tempPicOrderCnt;
//pic_order_cnt_lsb=u(&q1,tempPicOrderCnt);
//fatal(EXIT_BUG_BUG, "AVC: pic_order_cnt_type != 0 not yet supported.");
//fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type != 0 not yet supported.");
//TODO
// Calculate picture order count (POC) according to 8.2.1
}
@@ -893,11 +967,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
// 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 && frames_since_last_gop <= 3) // Used to be == 1, but the sample file
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;
dbg_print(CCX_DMT_TIME, "Ignoring this reference pic.\n");
dbg_print(CCX_DMT_TIME, "Ignoring this reference pic.\n");
}
// if slices are buffered - flush
@@ -910,10 +984,10 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
// Flush buffered cc blocks before doing the housekeeping
if (has_ccdata_buffered)
{
process_hdcc();
process_hdcc(ctx, sub);
}
last_gop_length = frames_since_last_gop;
frames_since_last_gop=0;
ctx->last_gop_length = ctx->frames_since_last_gop;
ctx->frames_since_last_gop=0;
last_gop_maxtref = maxtref;
maxtref = 0;
lastmaxidx = maxidx;
@@ -963,11 +1037,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
// Set maxtref
if( current_tref > maxtref ) {
maxtref = 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 > last_gop_length*1.5 ) {
if ( last_gop_maxtref > ctx->last_gop_length*1.5 ) {
current_tref = current_tref/2;
}
}
@@ -1006,7 +1080,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
}
if ( lastmaxidx == -1) {
// Set temporal reference to zero on minimal index and in the first GOP
// to avoid setting a wrong fts_offset
// to avoid setting a wrong fts_offset
current_tref = 0;
}
}
@@ -1026,7 +1100,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
(unsigned) (sync_pts));
dbg_print(CCX_DMT_TIME, " - %s since GOP: %2u",
slice_types[slice_type],
(unsigned) (frames_since_last_gop));
(unsigned) (ctx->frames_since_last_gop));
dbg_print(CCX_DMT_TIME, " b:%lld frame# %lld\n", bottom_field_flag, frame_num);
// sync_pts is (was) set when current_tref was zero
@@ -1040,13 +1114,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
}
total_frames_count++;
frames_since_last_gop++;
ctx->frames_since_last_gop++;
store_hdcc(cc_data, cc_count, curridx, fts_now);
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;
//exit(1);
}
// max_dec_frame_buffering .. Max frames in buffer

View File

@@ -1,4 +1,4 @@
#include "ccextractor.h"
#include "lib_ccx.h"
// Hold functions to read streams on a bit or byte oriented basis
// plus some data related helper functions.
@@ -22,7 +22,7 @@ int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char *
bstr->_i_bpos = 0;
if(bstr->bitsleft < 0)
{
{
// See if we can somehow recover of this disaster by reporting the problem instead of terminating.
mprint ( "init_bitstream: bitstream has negative length!");
return 1;
@@ -40,11 +40,11 @@ uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
uint64_t res = 0;
if(bnum > 64)
fatal(EXIT_BUG_BUG, "next_bits: 64 is maximum bit number, argument: %u!", bnum);
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: 64 is maximum bit number, argument: %u!", bnum);
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(EXIT_BUG_BUG, "next_bits: bitstream has negative length!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: bitstream has negative length!");
// Keep a negative bitstream.bitsleft, but correct it.
if (bstr->bitsleft <= 0)
@@ -67,7 +67,7 @@ uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
if(vbit < 1 || vbit > 8)
{
fatal(EXIT_BUG_BUG, "next_bits: Illegal bit position value %d!", vbit);
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Illegal bit position value %d!", vbit);
}
while( 1 )
@@ -75,7 +75,7 @@ uint64_t next_bits(struct bitstream *bstr, unsigned bnum)
if(vpos >= bstr->end)
{
// We should not get here ...
fatal(EXIT_BUG_BUG, "next_bits: Reading after end of data ...");
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bits: Reading after end of data ...");
}
res |= (*vpos & (0x01 << (vbit-1)) ? 1 : 0);
@@ -130,7 +130,7 @@ int skip_bits(struct bitstream *bstr, unsigned bnum)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(EXIT_BUG_BUG, "skip_bits: bitstream has negative length!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "skip_bits: bitstream has negative length!");
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
@@ -167,13 +167,13 @@ int is_byte_aligned(struct bitstream *bstr)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(EXIT_BUG_BUG, "is_byte_aligned: bitstream has negative length!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: bitstream has negative length!");
int vbit = bstr->bpos;
if(vbit == 0 || vbit > 8)
{
fatal(EXIT_BUG_BUG, "is_byte_aligned: Illegal bit position value %d!\n", vbit);
fatal(CCX_COMMON_EXIT_BUG_BUG, "is_byte_aligned: Illegal bit position value %d!\n", vbit);
}
if (vbit == 8)
@@ -188,13 +188,13 @@ void make_byte_aligned(struct bitstream *bstr)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(EXIT_BUG_BUG, "make_byte_aligned: bitstream has negative length!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: bitstream has negative length!");
int vbit = bstr->bpos;
if(vbit == 0 || vbit > 8)
{
fatal(EXIT_BUG_BUG, "make_byte_aligned: Illegal bit position value %d!\n", vbit);
fatal(CCX_COMMON_EXIT_BUG_BUG, "make_byte_aligned: Illegal bit position value %d!\n", vbit);
}
// Keep a negative bstr->bitsleft, but correct it.
@@ -226,7 +226,7 @@ unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum)
{
// Sanity check
if(bstr->end - bstr->pos < 0)
fatal(EXIT_BUG_BUG, "next_bytes: bitstream has negative length!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "next_bytes: bitstream has negative length!");
// Keep a negative bstr->bitsleft, but correct it.
if (bstr->bitsleft < 0)
@@ -294,17 +294,17 @@ uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
case 8:
break;
default:
fatal (EXIT_BUG_BUG, "bitstream_get_num: Illegal precision value [%u]!",
fatal (CCX_COMMON_EXIT_BUG_BUG, "bitstream_get_num: Illegal precision value [%u]!",
bytes);
break;
}
for (unsigned i=0;i<bytes;i++)
{
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
unsigned char uc=*ucpos;
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
unsigned char uc=*ucpos;
rval=(rval<<8) + uc;
}
return rval;
return rval;
}
@@ -329,7 +329,7 @@ int64_t se(struct bitstream *bstr)
int64_t res = 0;
res = ue(bstr);
// The following function might truncate when res+1 overflows
//res = (res+1)/2 * (res % 2 ? 1 : -1);
// Use this:

View File

@@ -3,8 +3,8 @@
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
{
unsigned char c1='?';
if (c<0x80)
{
if (c<0x80)
{
// Regular line-21 character set, mostly ASCII except these exceptions
switch (c)
{
@@ -16,7 +16,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
break;
case 0x5e: // lowercase i, acute accent
c1=0xed;
break;
break;
case 0x5f: // lowercase o, acute accent
c1=0xf3;
break;
@@ -45,25 +45,25 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
switch (c)
{
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
case 0x80: // Registered symbol (R)
c1=0xae;
break;
break;
case 0x81: // degree sign
c1=0xb0;
break;
case 0x82: // 1/2 symbol
case 0x82: // 1/2 symbol
c1=0xbd;
break;
case 0x83: // Inverted (open) question mark
case 0x83: // Inverted (open) question mark
c1=0xbf;
break;
case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1
break;
case 0x85: // Cents symbol
break;
case 0x85: // Cents symbol
c1=0xa2;
break;
case 0x86: // Pounds sterling
case 0x86: // Pounds sterling
c1=0xa3;
break;
case 0x87: // Music note - Not in latin 1, so we use 'pilcrow'
@@ -73,7 +73,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
c1=0xe0;
break;
case 0x89: // transparent space, we make it regular
c1=0x20;
c1=0x20;
break;
case 0x8a: // lowercase e, grave accent
c1=0xe8;
@@ -82,7 +82,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
c1=0xe2;
break;
case 0x8c: // lowercase e, circumflex accent
c1=0xea;
c1=0xea;
break;
case 0x8d: // lowercase i, circumflex accent
c1=0xee;
@@ -114,19 +114,19 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
c1=0xfc;
break;
case 0x96: // apostrophe
c1=0x27;
c1=0x27;
break;
case 0x97: // inverted exclamation mark
case 0x97: // inverted exclamation mark
c1=0xa1;
break;
case 0x98: // asterisk
c1=0x2a;
c1=0x2a;
break;
case 0x99: // apostrophe (yes, duped). See CCADI source code.
c1=0x27;
c1=0x27;
break;
case 0x9a: // em dash
c1=0x2d;
c1=0x2d;
break;
case 0x9b: // copyright sign
c1=0xa9;
@@ -137,17 +137,17 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
c1=0x2e;
break;
case 0x9e: // Quoatation mark
c1=0x22;
c1=0x22;
break;
case 0x9f: // Quoatation mark
c1=0x22;
c1=0x22;
break;
case 0xa0: // uppercase A, grave accent
c1=0xc0;
break;
case 0xa1: // uppercase A, circumflex
c1=0xc2;
break;
break;
case 0xa2: // uppercase C with cedilla
c1=0xc7;
break;
@@ -223,7 +223,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
c1=0x7b;
break;
case 0xba: // Closing curly brace
c1=0x7d;
c1=0x7d;
break;
case 0xbb: // Backslash
c1=0x5c;
@@ -234,17 +234,17 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
case 0xbd: // Underscore
c1=0x5f;
break;
case 0xbe: // Pipe (broken bar)
case 0xbe: // Pipe (broken bar)
c1=0xa6;
break;
case 0xbf: // Tilde
c1=0x7e;
c1=0x7e;
break;
case 0xc0: // Uppercase A, umlaut
case 0xc0: // Uppercase A, umlaut
c1=0xc4;
break;
case 0xc1: // Lowercase A, umlaut
c1=0xe3;
c1=0xe3;
break;
case 0xc2: // Uppercase O, umlaut
c1=0xd6;
@@ -260,10 +260,10 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
break;
case 0xc6: // Currency symbol
c1=0xa4;
break;
break;
case 0xc7: // Vertical bar
c1=0x7c;
break;
break;
case 0xc8: // Uppercase A, ring
c1=0xc5;
break;
@@ -284,7 +284,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
*buffer='?'; // I'll do it eventually, I promise
break; // This are weird chars anyway
}
*buffer=c1;
*buffer=c1;
}
void get_char_in_unicode (unsigned char *buffer, unsigned char c)
@@ -292,7 +292,7 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
unsigned char c1,c2;
switch (c)
{
case 0x84: // Trademark symbol (TM)
case 0x84: // Trademark symbol (TM)
c2=0x21;
c1=0x22;
break;
@@ -307,7 +307,7 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
case 0xcc: // Upper left corner
c2=0x23;
c1=0x1c;
break;
break;
case 0xcd: // Upper right corner
c2=0x23;
c1=0x1d;
@@ -320,7 +320,7 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
c2=0x23;
c1=0x1f;
break;
default: // Everything else, same as latin-1 followed by 00
default: // Everything else, same as latin-1 followed by 00
get_char_in_latin_1 (&c1,c);
c2=0;
break;
@@ -384,10 +384,10 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
switch (c)
{
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
case 0x80: // Registered symbol (R)
*buffer=0xc2;
*(buffer+1)=0xae;
*(buffer+1)=0xae;
return 2;
case 0x81: // degree sign
*buffer=0xc2;
@@ -414,7 +414,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*buffer=0xc2;
*(buffer+1)=0xa3;
return 2;
case 0x87: // Music note
case 0x87: // Music note
*buffer=0xe2;
*(buffer+1)=0x99;
*(buffer+2)=0xaa;
@@ -424,7 +424,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*(buffer+1)=0xa0;
return 2;
case 0x89: // transparent space, we make it regular
*buffer=0x20;
*buffer=0x20;
return 1;
case 0x8a: // lowercase e, grave accent
*buffer=0xc3;
@@ -477,20 +477,20 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*(buffer+1)=0xbc;
return 2;
case 0x96: // apostrophe
*buffer=0x27;
*buffer=0x27;
return 1;
case 0x97: // inverted exclamation mark
*buffer=0xc2;
*(buffer+1)=0xa1;
return 2;
case 0x98: // asterisk
*buffer=0x2a;
*buffer=0x2a;
return 1;
case 0x99: // Plain single quote
*buffer=0x27;
*buffer=0x27;
return 1;
case 0x9a: // em dash
*buffer=0xe2;
*buffer=0xe2;
*(buffer+1)=0x80;
*(buffer+2)=0x94;
return 3;
@@ -498,23 +498,23 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*buffer=0xc2;
*(buffer+1)=0xa9;
return 2;
case 0x9c: // Service mark
*buffer=0xe2;
case 0x9c: // Service mark
*buffer=0xe2;
*(buffer+1)=0x84;
*(buffer+2)=0xa0;
return 3;
case 0x9d: // Round bullet
*buffer=0xe2;
*buffer=0xe2;
*(buffer+1)=0x80;
*(buffer+2)=0xa2;
return 3;
case 0x9e: // Opening double quotes
*buffer=0xe2;
*buffer=0xe2;
*(buffer+1)=0x80;
*(buffer+2)=0x9c;
return 3;
case 0x9f: // Closing double quotes
*buffer=0xe2;
*buffer=0xe2;
*(buffer+1)=0x80;
*(buffer+2)=0x9d;
return 3;
@@ -624,7 +624,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*buffer=0x7b;
return 1;
case 0xba: // Closing curly brace
*buffer=0x7d;
*buffer=0x7d;
return 1;
case 0xbb: // Backslash
*buffer=0x5c;
@@ -636,26 +636,26 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*buffer=0x5f;
return 1;
case 0xbe: // Pipe (broken bar)
*buffer=0xc2;
*buffer=0xc2;
*(buffer+1)=0xa6;
return 2;
case 0xbf: // Tilde
*buffer=0x7e; // Not sure
return 1;
case 0xc0: // Uppercase A, umlaut
*buffer=0xc3;
*buffer=0xc3;
*(buffer+1)=0x84;
return 2;
case 0xc1: // Lowercase A, umlaut
*buffer=0xc3;
*buffer=0xc3;
*(buffer+1)=0xa4;
return 2;
case 0xc2: // Uppercase O, umlaut
*buffer=0xc3;
*buffer=0xc3;
*(buffer+1)=0x96;
return 2;
case 0xc3: // Lowercase o, umlaut
*buffer=0xc3;
*buffer=0xc3;
*(buffer+1)=0xb6;
return 2;
case 0xc4: // Esszett (sharp S)
@@ -671,7 +671,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*(buffer+1)=0xa4;
return 2;
case 0xc7: // Vertical bar
*buffer=0x7c;
*buffer=0x7c;
return 1;
case 0xc8: // Uppercase A, ring
*buffer=0xc3;
@@ -709,7 +709,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
*(buffer+1)=0x8c;
*(buffer+2)=0x9f;
return 3;
default: //
default: //
*buffer='?'; // I'll do it eventually, I promise
return 1; // This are weird chars anyway
}
@@ -726,35 +726,35 @@ unsigned char cctolower (unsigned char c)
case 0x90: // capital letter A with acute
return 0x2a;
case 0x91: // capital letter E with acute
return 0x5c;
return 0x5c;
case 0x92: // capital letter O with acute
return 0x5f;
return 0x5f;
case 0x93: // capital letter U with acute
return 0x60;
return 0x60;
case 0xa2: // uppercase C with cedilla
return 0x7b;
return 0x7b;
case 0xa0: // uppercase A, grave accent
return 0x88;
return 0x88;
case 0xa3: // uppercase E, grave accent
return 0x8a;
return 0x8a;
case 0xa1: // uppercase A, circumflex
return 0x8b;
return 0x8b;
case 0xa4: // uppercase E, circumflex
return 0x8c;
return 0x8c;
case 0xa7: // uppercase I, circumflex
return 0x8d;
return 0x8d;
case 0xaa: // uppercase O, circumflex
return 0x8e;
return 0x8e;
case 0xad: // uppercase U, circumflex
return 0x8f;
return 0x8f;
case 0x94: // capital letter U with diaresis
return 0x95;
return 0x95;
case 0xa5: // capital letter E with diaresis
return 0xa6;
return 0xa6;
case 0xa8: // uppercase I, with diaresis
return 0xa9;
return 0xa9;
case 0xab: // uppercase U, grave accent
return 0xac;
return 0xac;
case 0xb0: // Uppercase A, tilde
return 0xb1;
case 0xb2: // Uppercase I, acute accent
@@ -820,21 +820,21 @@ unsigned char cctoupper (unsigned char c)
case 0xac: // lowercase u, grave accent
return 0xab;
case 0xb1: // Lowercase a, tilde
return 0xb0;
return 0xb0;
case 0xb4: // Lowercase i, grave accent
return 0xb3;
case 0xb6: // Lowercase o, grave accent
return 0xb5;
case 0xb8: // Lowercase o, tilde
return 0xb5;
case 0xb8: // Lowercase o, tilde
return 0xb7;
case 0xc1: // Lowercase A, umlaut
return 0xc0;
case 0xc1: // Lowercase A, umlaut
return 0xc0;
case 0xc3: // Lowercase o, umlaut
return 0xc2;
case 0xc9: // Lowercase A, ring
return 0xc8;
return 0xc8;
case 0xcb: // Lowercase o, slash
return 0xca;
return 0xca;
}
return c;
}

View File

@@ -0,0 +1,10 @@
#ifndef __CCX_COMMON_CHAR_ENCODING__
#define __CCX_COMMON_CHAR_ENCODING__
void get_char_in_latin_1(unsigned char *buffer, unsigned char c);
void get_char_in_unicode(unsigned char *buffer, unsigned char c);
int get_char_in_utf_8(unsigned char *buffer, unsigned char c);
unsigned char cctolower(unsigned char c);
unsigned char cctoupper(unsigned char c);
#endif

View File

@@ -0,0 +1,65 @@
#include "ccx_common_common.h"
/* printf() for fd instead of FILE*, since dprintf is not portable */
void fdprintf(int fd, const char *fmt, ...)
{
/* Guess we need no more than 100 bytes. */
int n, size = 100;
char *p, *np;
va_list ap;
if (fd < 0)
return;
if ((p = (char *)malloc(size)) == NULL)
return;
while (1)
{
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
{
write(fd, p, n);
free(p);
return;
}
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n + 1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if ((np = (char *)realloc(p, size)) == NULL)
{
free(p);
return;
}
else {
p = np;
}
}
}
/* Converts the given milli to separate hours,minutes,seconds and ms variables */
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,
unsigned *seconds, unsigned *ms)
{
// LLONG milli = (LLONG) ((ccblock*1000)/29.97);
*ms = (unsigned)(milli % 1000); // milliseconds
milli = (milli - *ms) / 1000; // Remainder, in seconds
*seconds = (int)(milli % 60);
milli = (milli - *seconds) / 60; // Remainder, in minutes
*minutes = (int)(milli % 60);
milli = (milli - *minutes) / 60; // Remainder, in hours
*hours = (int)milli;
}
/* Frees the given pointer */
void freep(void *arg)
{
void **ptr = (void **)arg;
if (*ptr)
free(*ptr);
*ptr = NULL;
}

View File

@@ -0,0 +1,20 @@
#ifndef _CC_COMMON_COMMON
#define _CC_COMMON_COMMON
#include "ccx_common_platform.h"
// Define possible exit codes that will be passed on to the fatal function
#define CCX_COMMON_EXIT_FILE_CREATION_FAILED 5
#define CCX_COMMON_EXIT_UNSUPPORTED 9
#define EXIT_NOT_ENOUGH_MEMORY 500
#define CCX_COMMON_EXIT_BUG_BUG 1000
// 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);
extern int cc608_parity_table[256]; // From myth
#endif

View File

@@ -1,4 +1,4 @@
#include "ccextractor.h"
#include "ccx_common_constants.h"
// RCWT header (11 bytes):
//byte(s) value description (All values below are hex numbers, not
@@ -8,7 +8,7 @@
//4-5 0050 Program version number
//6-7 0001 File format version
//8-10 000000 Padding, required :-)
const unsigned char rcwt_header[11]={0xCC, 0xCC, 0xED, 0xCC, 0x00, 0x50, 0, 1, 0, 0, 0};
unsigned char rcwt_header[11]={0xCC, 0xCC, 0xED, 0xCC, 0x00, 0x50, 0, 1, 0, 0, 0};
const unsigned char BROADCAST_HEADER[]={0xff, 0xff, 0xff, 0xff};
const unsigned char LITTLE_ENDIAN_BOM[]={0xff, 0xfe};
@@ -123,3 +123,16 @@ enum
DTVCC_PACKET_DATA = 2,
DTVCC_PACKET_START = 3,
};
/**
* After Adding a new language here, dont forget
* to increase NB_LANGUAGE define ccx_common_constants.h
*/
const char *language[NB_LANGUAGE] =
{
"und",
"eng",
"fin",
"spa",
NULL
};

View File

@@ -1,6 +1,13 @@
#ifndef CCX_CONSTANTS_H
#define CCX_CONSTANTS_H
#include "stdio.h"
#ifndef __cplusplus
#define false 0
#define true 1
#endif
extern const char *framerates_types[16];
extern const double framerates_values[16];
@@ -20,7 +27,7 @@ extern const unsigned char lc4[2];
extern const unsigned char lc5[1];
extern const unsigned char lc6[1];
extern const unsigned char rcwt_header[11];
extern unsigned char rcwt_header[11];
#define ONEPASS 120 /* Bytes we can always look ahead without going out of limits */
#define BUFSIZE (2048*1024+ONEPASS) /* 2 Mb plus the safety pass */
@@ -32,17 +39,17 @@ extern const unsigned char rcwt_header[11];
#define XMLRPC_CHUNK_SIZE (64*1024) // 64 Kb per chunk, to avoid too many realloc()
enum ccx_debug_message_types
enum ccx_debug_message_types
{
/* Each debug message now belongs to one of these types. Use bitmaps in case
we want one message to belong to more than one type. */
/* Each debug message now belongs to one of these types. Use bitmaps in case
we want one message to belong to more than one type. */
CCX_DMT_PARSE=1, // Show information related to parsing the container
CCX_DMT_VIDES=2,// Show video stream related information
CCX_DMT_TIME=4, // Show GOP and PTS timing information
CCX_DMT_VERBOSE=8, // Show lots of debugging output
CCX_DMT_608=0x10, // Show CC-608 decoder debug?
CCX_DMT_708=0x20, // Show CC-708 decoder debug?
CCX_DMT_XDS=0x40, // Show XDS decoder debug?
CCX_DMT_DECODER_608=0x10, // Show CC-608 decoder debug?
CCX_DMT_708=0x20, // Show CC-708 decoder debug?
CCX_DMT_DECODER_XDS=0x40, // Show XDS decoder debug?
CCX_DMT_CBRAW=0x80, // Caption blocks with FTS timing
CCX_DMT_GENERIC_NOTICES=0x100, // Generic, always displayed even if no debug is selected
CCX_DMT_TELETEXT=0x200, // Show teletext debug?
@@ -74,7 +81,7 @@ enum ccx_avc_nal_types
CCX_NAL_TYPE_RESERVED_17 = 18,
CCX_NAL_TYPE_RESERVED_18 = 18,
CCX_NAL_TYPE_CODED_SLICE_AUXILIARY_PICTURE = 19,
CCX_NAL_TYPE_CODED_SLICE_EXTENSION = 20,
CCX_NAL_TYPE_CODED_SLICE_EXTENSION = 20,
CCX_NAL_TYPE_RESERVED_21 = 21,
CCX_NAL_TYPE_RESERVED_22 = 22,
CCX_NAL_TYPE_RESERVED_23 = 23,
@@ -101,7 +108,7 @@ enum ccx_stream_type
CCX_STREAM_TYPE_PRIVATE_MPEG2 = 0x06,
CCX_STREAM_TYPE_MHEG_PACKETS = 0x07,
CCX_STREAM_TYPE_MPEG2_ANNEX_A_DSM_CC = 0x08,
CCX_STREAM_TYPE_ITU_T_H222_1 = 0x09,
CCX_STREAM_TYPE_ITU_T_H222_1 = 0x09,
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_A = 0x0A,
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_B = 0x0B,
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_C = 0x0C,
@@ -117,13 +124,14 @@ enum ccx_stream_type
enum ccx_mpeg_descriptor
{
CCX_MPEG_DSC_REGISTRATION = 0x05,
CCX_MPEG_DSC_REGISTRATION = 0x05,
CCX_MPEG_DSC_DATA_STREAM_ALIGNMENT = 0x06,
CCX_MPEG_DSC_ISO639_LANGUAGE = 0x0A,
CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR = 0x45,
CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR = 0x46,
CCX_MPEG_DSC_TELETEXT_DESCRIPTOR = 0x56,
CCX_MPEG_DSC_DVB_SUBTITLE = 0x59,
CCX_MPEG_DESC_DATA_COMP = 0xfd,
};
@@ -138,7 +146,8 @@ enum ccx_datasource
{
CCX_DS_FILE=0,
CCX_DS_STDIN=1,
CCX_DS_NETWORK=2
CCX_DS_NETWORK=2,
CCX_DS_TCP=3
};
enum ccx_output_format
@@ -173,7 +182,9 @@ enum ccx_stream_mode_enum
CCX_SM_RCWT = 5, // Raw Captions With Time, not used yet.
CCX_SM_MYTH = 6, // Use the myth loop
CCX_SM_MP4 = 7, // MP4, ISO-
#ifdef WTV_DEBUG
CCX_SM_HEX_DUMP = 8, // Hexadecimal dump generated by wtvccdump
#endif
CCX_SM_WTV = 9,
CCX_SM_AUTODETECT = 16
};
@@ -212,11 +223,12 @@ typedef enum {
UNDEF = 0xff
} bool_t;
enum cxx_code_type
enum ccx_code_type
{
CCX_CODEC_ANY,
CCX_CODEC_TELETEXT,
CCX_CODEC_DVB,
CCX_CODEC_ISDB_CC,
CCX_CODEC_NONE,
};
/*
@@ -226,13 +238,13 @@ enum cxx_code_type
* @param desc descriptor tag given for each stream
*
* @return if descriptor tag is valid then it return 1 otherwise 0
*
*
*/
#define IS_VALID_TELETEXT_DESC(desc) ( ((desc) == CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR )|| \
( (desc) == CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR ) || \
( (desc) == CCX_MPEG_DSC_TELETEXT_DESCRIPTOR ) )
/*
* This macro to be used when you want to find out whether you
* should parse f_sel subtitle codec type or not
@@ -255,8 +267,6 @@ enum cxx_code_type
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
#define CCX_OF_TYPE_TEXT 1
#define CCX_OF_TYPE_IMAGE 2
#define NB_LANGUAGE 5
extern const char *language[NB_LANGUAGE];
#endif

View File

@@ -0,0 +1,110 @@
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "utility.h"
struct ccx_s_options ccx_options;
/* 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;
options->settings_608.force_rollup = 0;
options->settings_608.screens_to_process = -1;
options->settings_608.default_color = COL_TRANSPARENT; // Defaults to transparant/no-color.
/* 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->sentence_cap_file=NULL; // Extra words file?
options->live_stream=0; // 0 -> A regular file
options->messages_target=1; // 1=stdout
options->print_file_reports=0;
/* Levenshtein's parameters, for string comparison */
options->levdistmincnt=2; // Means 2 fails or less is "the same"...
options->levdistmaxpct=10; // ...10% or less is also "the same"
options->investigate_packets = 0; // Look for captions in all packets when everything else fails
options->fullbin=0; // Disable pruning of padding cc blocks
options->nosync=0; // Disable syncing
options->hauppauge_mode=0; // If 1, use PID=1003, process specially and so on
options->wtvconvertfix = 0; // Fix broken Windows 7 conversion
options->wtvmpeg2 = 0;
options->auto_myth = 2; // 2=auto
/* MP4 related stuff */
options->mp4vidtrack=0; // Process the video track even if a CC dedicated track exists.
/* General stuff */
options->usepicorder = 0; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
options->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->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.
options->send_to_srv = 0;
options->tcpport = NULL;
options->tcp_password = NULL;
options->tcp_desc = NULL;
options->srv_addr = NULL;
options->srv_port = NULL;
options->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;
// 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);
}

View File

@@ -0,0 +1,103 @@
#ifndef CCX_COMMON_OPTION_H
#define CCX_COMMON_OPTION_H
#include "ccx_common_timing.h"
#include "ccx_decoders_608.h"
#include "ccx_encoders_structs.h"
struct ccx_s_options // Options from user parameters
{
int extract; // Extract 1st, 2nd or both fields
int cc_channel; // Channel we want to dump in srt mode
int buffer_input;
int nofontcolor;
int notypesetting;
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
int print_file_reports;
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
/* 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;
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
>0 -> Live stream with a timeout of this value in seconds */
int messages_target; // 0 = nowhere (quiet), 1=stdout, 2=stderr
/* Levenshtein's parameters, for string comparison */
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
int investigate_packets; // Look for captions in all packets when everything else fails
int fullbin; // Disable pruning of padding cc blocks
int nosync; // Disable syncing
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
int wtvconvertfix; // Fix broken Windows 7 conversion
int wtvmpeg2;
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
/* MP4 related stuff */
unsigned mp4vidtrack; // Process the video track even if a CC dedicated track exists.
/* General settings */
int usepicorder; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
int autodash; // Add dashes (-) before each speaker automatically?
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;
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 **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
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;
};
extern struct ccx_s_options ccx_options;
void init_options (struct ccx_s_options *options);
#endif

View File

@@ -0,0 +1,113 @@
#ifndef CCX_PLATFORM_H
#define CCX_PLATFORM_H
// Default includes (cross-platform)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#define __STDC_FORMAT_MACROS
#ifdef _WIN32
#include <io.h>
#include <ws2tcpip.h>
#include <windows.h>
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#include "inttypes.h"
#define UINT64_MAX _UI64_MAX
typedef int socklen_t;
typedef int ssize_t;
typedef uint32_t in_addr_t;
#ifndef IN_CLASSD
#define IN_CLASSD(i) (((INT32)(i) & 0xf0000000) == 0xe0000000)
#define IN_MULTICAST(i) IN_CLASSD(i)
#endif
#include <direct.h>
#define mkdir(path, mode) _mkdir(path)
#ifndef snprintf
// Added ifndef because VS2013 warns for macro redefinition.
#define snprintf(buf, len, fmt, ...) _snprintf(buf, len, fmt, __VA_ARGS__)
#endif
#define sleep(sec) Sleep((sec) * 1000)
#include <fcntl.h>
#else // _WIN32
#include <unistd.h>
#define __STDC_LIMIT_MACROS
#include <inttypes.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif // _WIN32
#include "disable_warnings.h"
#ifdef _MSC_VER
#include "stdintmsc.h"
// Don't bug me with strcpy() deprecation warnings
#pragma warning(disable : 4996)
#else
#include <stdint.h>
#endif
#ifdef __OpenBSD__
#define FOPEN64 fopen
#define OPEN open
#define FSEEK fseek
#define FTELL ftell
#define LSEEK lseek
#define FSTAT fstat
#else
#ifdef _WIN32
#define OPEN _open
// 64 bit file functions
#if defined(MSC_VER)
extern "C" int __cdecl _fseeki64(FILE *, __int64, int);
extern "C" __int64 __cdecl _ftelli64(FILE *);
#define FSEEK _fseeki64
#define FTELL _ftelli64
#else
// For MinGW
#define FSEEK fseeko64
#define FTELL ftello64
#endif
#define TELL _telli64
#define LSEEK _lseeki64
typedef struct _stati64 FSTATSTRUCT;
#else
// Linux internally maps these functions to 64bit usage,
// if _FILE_OFFSET_BITS macro is set to 64
#define FOPEN64 fopen
#define OPEN open
#define LSEEK lseek
#define FSEEK fseek
#define FTELL ftell
#define FSTAT fstat
#define TELL tell
#include <stdint.h>
#endif
#endif
#ifndef int64_t_C
#define int64_t_C(c) (c ## LL)
#define uint64_t_C(c) (c ## ULL)
#endif
#ifndef O_BINARY
#define O_BINARY 0 // Not present in Linux because it's always binary
#endif
typedef int64_t LLONG;
#endif // CCX_PLATFORM_H

View File

@@ -0,0 +1,53 @@
#ifndef _CC_COMMON_STRUCTS
#define _CC_COMMON_STRUCTS
enum ccx_common_logging_gui {
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME, // Called with xds_program_name
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR, // Called with current_xds_min, current_xds_hour, current_xds_date, current_xds_month
CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION, // Called with line_num, xds_desc
CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS // Called with current_xds_call_letters
};
struct ccx_common_logging_t {
int debug_mask; // The debug mask that is used to determine if things should be printed or not.
void(*fatal_ftn) (int exit_code, const char *fmt, ...); // Used when an unrecoverable error happens. This should log output/save the error and then exit the program.
void(*debug_ftn) (LLONG mask, const char *fmt, ...); // Used to process debug output. Mask can be ignored (custom set by debug_mask).
void(*log_ftn)(const char *fmt, ...); // Used to print things. Replacement of standard printf, to allow more control.
void(*gui_ftn)(enum ccx_common_logging_gui message_type, ...); // Used to display things in a gui (if appropriate). Is called with the message_type and appropriate variables (described in enum)
};
extern struct ccx_common_logging_t ccx_common_logging;
enum subtype
{
CC_BITMAP,
CC_608,
CC_TEXT,
};
/**
* Raw Subtitle struct used as output of decoder (cc608)
* and input for encoder (sami, srt, transcript or smptett etc)
*/
struct cc_subtitle
{
/**
* A generic data which contain data according to decoder
* just now only struct cc_eia608_screen is placed here
* @warn decoder cant output multiple types of data
*/
void *data;
/** number of data */
unsigned int nb_data;
/** type of subtitle */
enum subtype type;
/* 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;
};
#endif

View File

@@ -1,64 +1,89 @@
#include "ccextractor.h"
#include "ccx_common_timing.h"
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#include "ccx_common_common.h"
/* Provide the current time since the file (or the first file) started
* in ms using PTS time information.
* Requires: frames_since_ref_time, current_tref
*/
// int ignore_fts=1; // Don't do any kind of timing stuff. Assume it's being done externally (as happens in MP4)
// 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;
struct ccx_common_timing_settings_t ccx_common_timing_settings;
void ccx_common_timing_init(LLONG *file_position,int no_sync)
{
ccx_common_timing_settings.disable_sync_check = 0;
ccx_common_timing_settings.is_elementary_stream = 0;
ccx_common_timing_settings.file_position = file_position;
ccx_common_timing_settings.no_sync = no_sync;
}
void set_fts(void)
{
int pts_jump = 0;
// ES don't have PTS unless GOP timing is used
if (!pts_set && stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND)
if (!pts_set && ccx_common_timing_settings.is_elementary_stream)
return;
// First check for timeline jump (only when min_pts was
// set (implies sync_pts).
// First check for timeline jump (only when min_pts was set (implies sync_pts)).
int dif = 0;
if (pts_set == 2)
{
dif=(int) (current_pts-sync_pts)/MPEG_CLOCK_FREQ;
// Used to distinguish gaps with missing caption information from
// jumps in the timeline. (Currently only used for dvr-ms/NTSC
// recordings)
if ( CaptionGap )
dif = 0;
if (ccx_common_timing_settings.disable_sync_check){
// Disables sync check. Used for several input formats.
dif = 0;
}
// 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 (stream_mode)
{
case CCX_SM_MCPOODLESRAW:
case CCX_SM_RCWT:
case CCX_SM_MP4:
case CCX_SM_HEX_DUMP:
dif = 0;
break;
default:
break;
}
if (dif < -0.2 || dif >=max_dif )
if (dif < -0.2 || dif >= max_dif )
{
// ATSC specs: More than 3501 ms means missing component
mprint ("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int) dif, past);
mprint ("Last sync PTS value: %lld\n",sync_pts);
mprint ("Current PTS value: %lld\n",current_pts);
ccx_common_logging.log_ftn ("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int) dif, *ccx_common_timing_settings.file_position);
ccx_common_logging.log_ftn ("Last sync PTS value: %lld\n",sync_pts);
ccx_common_logging.log_ftn ("Current PTS value: %lld\n",current_pts);
pts_jump = 1;
pts_big_change=1;
// Discard the gap if it is not on an I-frame or temporal reference
// zero.
// Discard the gap if it is not on an I-frame or temporal reference zero.
if(current_tref != 0 && current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME)
{
fts_now = fts_max;
mprint ("Change did not occur on first frame - probably a broken GOP\n");
ccx_common_logging.log_ftn ("Change did not occur on first frame - probably a broken GOP\n");
return;
}
}
@@ -89,7 +114,7 @@ void set_fts(void)
}
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
// 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;
@@ -101,15 +126,15 @@ void set_fts(void)
-frames_since_ref_time+1)
*1000.0/current_fps);
}
dbg_print(CCX_DMT_TIME, "\nFirst sync time PTS: %s %+lldms (time before this PTS)\n",
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 );
dbg_print(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n",
ccx_common_logging.debug_ftn(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n",
total_frames_count, frames_since_ref_time);
}
// -nosync diasbles syncing
if (pts_jump && !ccx_options.nosync)
// -nosync disables syncing
if (pts_jump && !ccx_common_timing_settings.no_sync)
{
// The current time in the old time base is calculated using
// sync_pts (set at the beginning of the last GOP) plus the
@@ -130,7 +155,7 @@ void set_fts(void)
// Set min_pts = sync_pts as this is used for fts_now
min_pts = sync_pts;
dbg_print(CCX_DMT_TIME, "\nNew min PTS time: %s %+lldms (time before this PTS)\n",
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 );
}
@@ -158,7 +183,7 @@ void set_fts(void)
else
{
// No PTS info at all!!
fatal(EXIT_BUG_BUG,
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG,
"No PTS info. Please write bug report.");
}
}
@@ -185,7 +210,7 @@ LLONG get_fts(void)
fts = fts_now + fts_global + cb_708*1001/30;
break;
default:
fatal(EXIT_BUG_BUG, "Cannot be reached!");
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
}
return fts;
@@ -206,7 +231,7 @@ char *print_mstime2buf( LLONG mstime , char *buf )
int signoffset = (mstime < 0 ? 1 : 0);
if (mstime<0) // Avoid loss of data warning with abs()
mstime=-mstime;
mstime=-mstime;
hh = (unsigned) (mstime/1000/60/60);
mm = (unsigned) (mstime/1000/60 - 60*hh);
ss = (unsigned) (mstime/1000 - 60*(mm + 60*hh));
@@ -233,9 +258,9 @@ void print_debug_timing( void )
// for uninitialized min_pts
LLONG tempmin_pts = (min_pts==0x01FFFFFFFFLL ? sync_pts : min_pts);
mprint("Sync time stamps: PTS: %s ",
ccx_common_logging.log_ftn("Sync time stamps: PTS: %s ",
print_mstime((sync_pts)/(MPEG_CLOCK_FREQ/1000)) );
mprint("GOP: %s \n", print_mstime(gop_time.ms));
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);
@@ -243,13 +268,13 @@ void print_debug_timing( void )
LLONG ptslenms = (unsigned)((sync_pts-tempmin_pts)/(MPEG_CLOCK_FREQ/1000)
+ fts_offset);
mprint("Last FTS: %s",
ccx_common_logging.log_ftn("Last FTS: %s",
print_mstime(get_fts_max()));
mprint(" GOP start FTS: %s\n",
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
mprint("Max FTS diff. to PTS: %6lldms GOP: %6lldms\n\n",
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);
}
@@ -264,9 +289,9 @@ void calculate_ms_gop_time (struct gop_time_code *g)
int gop_accepted(struct gop_time_code* g )
{
if (! ((g->time_code_hours <= 23)
&& (g->time_code_minutes <= 59)
&& (g->time_code_seconds <= 59)
if (! ((g->time_code_hours <= 23)
&& (g->time_code_minutes <= 59)
&& (g->time_code_seconds <= 59)
&& (g->time_code_pictures <= 59)))
return 0;

View File

@@ -0,0 +1,72 @@
#ifndef __Timing_H__
#include "ccx_common_platform.h"
struct gop_time_code
{
int drop_frame_flag;
int time_code_hours;
int time_code_minutes;
int marker_bit;
int time_code_seconds;
int time_code_pictures;
int inited;
LLONG ms;
};
struct ccx_common_timing_settings_t {
int disable_sync_check; // If 1, timeline jumps will be ignored. This is important in several input formats that are assumed to have correct timing, no matter what.
int no_sync; // If 1, there will be no sync at all. Mostly useful for debugging.
int is_elementary_stream; // Needs to be set, as it's used in set_fts.
LLONG *file_position; // The position of the file
};
extern struct ccx_common_timing_settings_t ccx_common_timing_settings;
struct ccx_boundary_time
{
int hh,mm,ss;
LLONG time_in_ms;
int set;
};
// 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);
char *print_mstime(LLONG mstime);
char *print_mstime2buf(LLONG mstime, char *buf);
void print_debug_timing(void);
int gop_accepted(struct gop_time_code* g);
void calculate_ms_gop_time(struct gop_time_code *g);
#define __Timing_H__
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,154 @@
#ifndef __608_H__
#include "ccx_common_platform.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
extern LLONG ts_start_of_xds;
/*
This variable (ccx_decoder_608_report) holds data on the cc channels & xds packets that are encountered during file parse.
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
for the report functionality.
*/
struct ccx_decoder_608_report
{
unsigned xds : 1;
unsigned cc_channels[4];
};
typedef struct ccx_decoder_608_settings
{
int direct_rollup; // Write roll-up captions directly instead of line by line?
int force_rollup; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
int no_rollup; // If 1, write one line at a time
unsigned char default_color; // Default color to use.
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
} ccx_decoder_608_settings;
typedef struct ccx_decoder_608_context
{
ccx_decoder_608_settings settings;
eia608_screen buffer1;
eia608_screen buffer2;
int cursor_row, cursor_column;
int visible_buffer;
int screenfuls_counter; // Number of meaningful screenfuls written
LLONG current_visible_start_ms; // At what time did the current visible buffer became so?
enum cc_modes mode;
unsigned char last_c1, last_c2;
int channel; // Currently selected channel
unsigned char current_color; // Color we are currently using to write
unsigned char font; // Font we are currently using to write
int rollup_base_row;
LLONG ts_start_of_current_line; /* Time at which the first character for current line was received, =-1 no character received yet */
LLONG ts_last_char_received; /* Time at which the last written character was received, =-1 no character received yet */
int new_channel; // The new channel after a channel change
int my_field; // Used for sanity checks
int my_channel; // Used for sanity checks
long bytes_processed_608; // To be written ONLY by process_608
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;
LLONG subs_delay; // ms to delay (or advance) subs
enum ccx_output_format output_format; // What kind of output format should be used?
} 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];
typedef enum ccx_decoder_608_color_code
{
COL_WHITE = 0,
COL_GREEN = 1,
COL_BLUE = 2,
COL_CYAN = 3,
COL_RED = 4,
COL_YELLOW = 5,
COL_MAGENTA = 6,
COL_USERDEFINED = 7,
COL_BLACK = 8,
COL_TRANSPARENT = 9
} ccx_decoder_608_color_code;
enum font_bits
{
FONT_REGULAR = 0,
FONT_ITALICS = 1,
FONT_UNDERLINED = 2,
FONT_UNDERLINED_ITALICS = 3
};
enum command_code
{
COM_UNKNOWN = 0,
COM_ERASEDISPLAYEDMEMORY = 1,
COM_RESUMECAPTIONLOADING = 2,
COM_ENDOFCAPTION = 3,
COM_TABOFFSET1 = 4,
COM_TABOFFSET2 = 5,
COM_TABOFFSET3 = 6,
COM_ROLLUP2 = 7,
COM_ROLLUP3 = 8,
COM_ROLLUP4 = 9,
COM_CARRIAGERETURN = 10,
COM_ERASENONDISPLAYEDMEMORY = 11,
COM_BACKSPACE = 12,
COM_RESUMETEXTDISPLAY = 13,
COM_ALARMOFF =14,
COM_ALARMON = 15,
COM_DELETETOENDOFROW = 16,
COM_RESUMEDIRECTCAPTIONING = 17,
// Non existing commands we insert to have the decoder
// special stuff for us.
COM_FAKE_RULLUP1 = 18
};
void ccx_decoder_608_dinit_library(void **ctx);
/*
*
*/
ccx_decoder_608_context* ccx_decoder_608_init_library(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);
/**
* @param data raw cc608 data to be processed
*
* @param length length of data passed
*
* @param context context of cc608 where important information related to 608
* are stored.
*
* @param sub pointer to subtitle should be memset to 0 when passed first time
* subtitle are stored when structure return
*
* @return number of bytes used from data, -1 when any error is encountered
*/
int process608(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub);
/**
* Issue a EraseDisplayedMemory here so if there's any captions pending
* they get written to cc_subtitle
*/
void handle_end_of_data(ccx_decoder_608_context *context, struct cc_subtitle *sub);
int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub);
#define __608_H__
#endif

View File

@@ -1,10 +1,19 @@
#include "ccextractor.h"
#include <sys/stat.h>
#include "ccx_decoders_708.h"
#include "ccx_common_common.h"
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#include "ccx_common_timing.h"
/* Portions by Daniel Kristjansson, extracted from MythTV's source */
// #define DEBUG_708_PACKETS // Already working.
// #define DEBUG_708_PACKETS // Already working.
int do_cea708 = 0; // Process 708 data?
int cea708services[CCX_DECODERS_708_MAX_SERVICES]; // [] -> 1 for services to be processed
int ccx_decoders_708_report = 0;
int resets_708;
struct ccx_decoder_708_report_t ccx_decoder_708_report;
static unsigned char current_packet[MAX_708_PACKET_LENGTH]; // Length according to EIA-708B, part 5
static int current_packet_length=0;
static int last_seq=-1; // -1 -> No last sequence yet
@@ -24,27 +33,27 @@ const char *COMMANDS_C0[32]=
"BS", // 8 = Backspace
NULL, // 9 = Reserved
NULL, // A = Reserved
NULL, // B = Reserved
NULL, // B = Reserved
"FF", // C = FF
"CR", // D = CR
"HCR", // E = HCR
NULL, // F = Reserved
NULL, // F = Reserved
"EXT1",// 0x10 = EXT1,
NULL, // 0x11 = Reserved
NULL, // 0x12 = Reserved
NULL, // 0x13 = Reserved
NULL, // 0x14 = Reserved
NULL, // 0x15 = Reserved
NULL, // 0x11 = Reserved
NULL, // 0x12 = Reserved
NULL, // 0x13 = Reserved
NULL, // 0x14 = Reserved
NULL, // 0x15 = Reserved
NULL, // 0x16 = Reserved
NULL, // 0x17 = Reserved
NULL, // 0x17 = Reserved
"P16", // 0x18 = P16
NULL, // 0x19 = Reserved
NULL, // 0x1A = Reserved
NULL, // 0x1B = Reserved
NULL, // 0x1C = Reserved
NULL, // 0x1D = Reserved
NULL, // 0x1E = Reserved
NULL, // 0x1F = Reserved
NULL, // 0x19 = Reserved
NULL, // 0x1A = Reserved
NULL, // 0x1B = Reserved
NULL, // 0x1C = Reserved
NULL, // 0x1D = Reserved
NULL, // 0x1E = Reserved
NULL, // 0x1F = Reserved
};
struct S_COMMANDS_C1 COMMANDS_C1[32]=
@@ -64,7 +73,7 @@ struct S_COMMANDS_C1 COMMANDS_C1[32]=
{DLW,"DLW","DeleteWindows", 2},
{DLY,"DLY","Delay", 2},
{DLC,"DLC","DelayCancel", 1},
{RST,"RST","Reset", 1},
{RST,"RST","Reset", 1},
{SPA,"SPA","SetPenAttributes", 3},
{SPC,"SPC","SetPenColor", 4},
{SPL,"SPL","SetPenLocation", 3},
@@ -93,7 +102,7 @@ void clear_packet(void)
}
void cc708_service_reset(cc708_service_decoder *decoder)
{
{
// There's lots of other stuff that we need to do, such as canceling delays
for (int j=0;j<8;j++)
{
@@ -101,8 +110,8 @@ void cc708_service_reset(cc708_service_decoder *decoder)
decoder->windows[j].visible=0;
decoder->windows[j].memory_reserved=0;
decoder->windows[j].is_empty=1;
memset (decoder->windows[j].commands, 0,
sizeof (decoder->windows[j].commands));
memset (decoder->windows[j].commands, 0,
sizeof (decoder->windows[j].commands));
}
decoder->current_window=-1;
decoder->current_visible_start_ms=0;
@@ -112,16 +121,21 @@ void cc708_service_reset(cc708_service_decoder *decoder)
decoder->inited=1;
}
void cc708_reset()
void cc708_reset(struct lib_cc_decode *ctx)
{
dbg_print(CCX_DMT_708, ">>> Entry in cc708_reset()\n");
// Clear states of decoders
cc708_service_reset(&decoders[0]);
cc708_service_reset(&decoders[1]);
// Empty packet buffer
clear_packet();
last_seq=-1;
resets_708++;
ccx_common_logging.debug_ftn(CCX_DMT_708, ">>> Entry in cc708_reset()\n");
decoders[0].output_format = ctx->write_format;
decoders[1].output_format = ctx->write_format;
decoders[0].subs_delay = ctx->subs_delay;
decoders[1].subs_delay = ctx->subs_delay;
// Clear states of decoders
cc708_service_reset(&decoders[0]);
cc708_service_reset(&decoders[1]);
// Empty packet buffer
clear_packet();
last_seq=-1;
resets_708++;
}
int compWindowsPriorities (const void *a, const void *b)
@@ -143,47 +157,50 @@ void clearTV (cc708_service_decoder *decoder, int buffer) // Buffer => 1 or 2
void printTVtoSRT (cc708_service_decoder *decoder, int which)
{
if (decoder->output_format == CCX_OF_NULL)
return;
/* tvscreen *tv = (which==1)? &decoder->tv1:&decoder->tv2; */
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
LLONG ms_start= decoder->current_visible_start_ms;
LLONG ms_end = get_visible_end()+subs_delay;
LLONG ms_end = get_visible_end() + decoder->subs_delay;
int empty=1;
ms_start+=subs_delay;
ms_start+= decoder->subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return;
for (int i=0;i<75;i++)
{
{
for (int j=0;j<210;j++)
if (decoder->tv->chars[i][j]!=' ')
{
empty=0;
break;
}
if (!empty)
if (!empty)
break;
}
if (empty)
return; // Nothing to write
if (decoder->fh==-1) // File not yet open, do it now
{
mprint ("Creating %s\n", wbout1.filename);
decoder->fh=open (decoder->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
ccx_common_logging.log_ftn("Creating %s\n", decoder->filename); // originally wbout1.filename, but since line below uses decoder->filename, assume it's good to use?
decoder->fh= open(decoder->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
if (decoder->fh==-1)
{
fatal (EXIT_FILE_CREATION_FAILED, "Failed\n");
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n");
}
}
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];
char timeline[128];
decoder->srt_counter++;
sprintf (timeline,"%u\r\n",decoder->srt_counter);
write (decoder->fh,timeline,strlen (timeline));
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
h1,m1,s1,ms1, h2,m2,s2,ms2);
write (decoder->fh,timeline,strlen (timeline));
write (decoder->fh,timeline,strlen (timeline));
for (int i=0;i<75;i++)
{
int empty=1;
@@ -200,7 +217,7 @@ void printTVtoSRT (cc708_service_decoder *decoder, int which)
if (decoder->tv->chars[i][l]!=' ')
break;
for (int j=f;j<=l;j++)
write (decoder->fh,&decoder->tv->chars[i][j],1);
write (decoder->fh,&decoder->tv->chars[i][j],1);
write (decoder->fh,"\r\n",2);
}
}
@@ -213,7 +230,7 @@ void printTVtoConsole (cc708_service_decoder *decoder, int which)
char tbuf1[15],tbuf2[15];
print_mstime2buf (decoder->current_visible_start_ms,tbuf1);
print_mstime2buf (get_visible_end(),tbuf2);
dbg_print(CCX_DMT_GENERIC_NOTICES, "\r%s --> %s\n", tbuf1,tbuf2);
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "\r%s --> %s\n", tbuf1,tbuf2);
for (int i=0;i<75;i++)
{
int empty=1;
@@ -230,8 +247,8 @@ void printTVtoConsole (cc708_service_decoder *decoder, int which)
if (decoder->tv->chars[i][l]!=' ')
break;
for (int j=f;j<=l;j++)
dbg_print(CCX_DMT_GENERIC_NOTICES, "%c", decoder->tv->chars[i][j]);
dbg_print(CCX_DMT_GENERIC_NOTICES, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "%c", decoder->tv->chars[i][j]);
ccx_common_logging.debug_ftn(CCX_DMT_GENERIC_NOTICES, "\n");
}
}
}
@@ -267,13 +284,13 @@ void updateScreen (cc708_service_decoder *decoder)
if (decoder->windows[i].is_defined && decoder->windows[i].visible && !decoder->windows[i].is_empty)
wnd[visible++]=&decoder->windows[i];
}
qsort (wnd,visible,sizeof (int),compWindowsPriorities);
dbg_print(CCX_DMT_708, "Visible (and populated) windows in priority order: ");
qsort (wnd,visible,sizeof (e708Window *),compWindowsPriorities);
ccx_common_logging.debug_ftn(CCX_DMT_708, "Visible (and populated) windows in priority order: ");
for (int i=0;i<visible;i++)
{
dbg_print(CCX_DMT_708, "%d (%d) | ",wnd[i]->number, wnd[i]->priority);
ccx_common_logging.debug_ftn(CCX_DMT_708, "%d (%d) | ",wnd[i]->number, wnd[i]->priority);
}
dbg_print(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
for (int i=0;i<visible;i++)
{
int top,left;
@@ -320,7 +337,7 @@ void updateScreen (cc708_service_decoder *decoder)
default: // Shouldn't happen, but skip the window just in case
continue;
}
dbg_print(CCX_DMT_708, "For window %d: Anchor point -> %d, size %d:%d, real position %d:%d\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, "For window %d: Anchor point -> %d, size %d:%d, real position %d:%d\n",
wnd[i]->number, wnd[i]->anchor_point, wnd[i]->row_count,wnd[i]->col_count,
top,left);
if (top<0)
@@ -331,17 +348,17 @@ void updateScreen (cc708_service_decoder *decoder)
I708_SCREENGRID_ROWS - top : wnd[i]->row_count;
int copycols=left + wnd[i]->col_count >= I708_SCREENGRID_COLUMNS ?
I708_SCREENGRID_COLUMNS - left : wnd[i]->col_count;
dbg_print(CCX_DMT_708, "%d*%d will be copied to the TV.\n", copyrows, copycols);
ccx_common_logging.debug_ftn(CCX_DMT_708, "%d*%d will be copied to the TV.\n", copyrows, copycols);
for (int j=0;j<copyrows;j++)
{
memcpy (decoder->tv->chars[top+j],wnd[i]->rows[j],copycols);
}
}
}
decoder->current_visible_start_ms=get_visible_start();
}
/* This function handles future codes. While by definition we can't do any work on them, we must return
how many bytes would be consumed if these codes were supported, as defined in the specs.
/* This function handles future codes. While by definition we can't do any work on them, we must return
how many bytes would be consumed if these codes were supported, as defined in the specs.
Note: EXT1 not included */
// C2: Extended Miscellaneous Control Codes
// TODO: This code is completely untested due to lack of samples. Just following specs!
@@ -359,30 +376,30 @@ int handle_708_C2 (cc708_service_decoder *decoder, unsigned char *data, int data
int handle_708_C3 (cc708_service_decoder *decoder, unsigned char *data, int data_length)
{
if (data[0]<0x80 || data[0]>0x9F)
fatal (EXIT_BUG_BUG, "Entry in handle_708_C3 with an out of range value.");
ccx_common_logging.fatal_ftn (CCX_COMMON_EXIT_BUG_BUG, "Entry in handle_708_C3 with an out of range value.");
if (data[0]<=0x87) // 80-87...
return 5; // ... Five-byte control bytes (4 additional bytes)
else if (data[0]<=0x8F) // 88-8F ...
return 6; // ..Six-byte control codes (5 additional byte)
// If here, then 90-9F ...
// These are variable length commands, that can even span several segments
// (they allow even downloading fonts or graphics).
// These are variable length commands, that can even span several segments
// (they allow even downloading fonts or graphics).
// TODO: Implemen if a sample ever appears
fatal (EXIT_UNSUPPORTED, "This sample contains unsupported 708 data. PLEASE help us improve CCExtractor by submitting it.\n");
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_UNSUPPORTED, "This sample contains unsupported 708 data. PLEASE help us improve CCExtractor by submitting it.\n");
return 0; // Unreachable, but otherwise there's compilers warnings
}
// This function handles extended codes (EXT1 + code), from the extended sets
// G2 (20-7F) => Mostly unmapped, except for a few characters.
// G2 (20-7F) => Mostly unmapped, except for a few characters.
// G3 (A0-FF) => A0 is the CC symbol, everything else reserved for future expansion in EIA708-B
// C2 (00-1F) => Reserved for future extended misc. control and captions command codes
// TODO: This code is completely untested due to lack of samples. Just following specs!
// Returns number of used bytes, usually 1 (since EXT1 is not counted).
// Returns number of used bytes, usually 1 (since EXT1 is not counted).
int handle_708_extended_char (cc708_service_decoder *decoder, unsigned char *data, int data_length)
{
int used;
dbg_print(CCX_DMT_708, "In handle_708_extended_char, first data code: [%c], length: [%u]\n",data[0], data_length);
{
int used;
ccx_common_logging.debug_ftn(CCX_DMT_708, "In handle_708_extended_char, first data code: [%c], length: [%u]\n",data[0], data_length);
unsigned char c=0x20; // Default to space
unsigned char code=data[0];
if (/* data[i]>=0x00 && */ code<=0x1F) // Comment to silence warning
@@ -444,9 +461,9 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
const char *name=COMMANDS_C0[data[0]];
if (name==NULL)
name="Reserved";
dbg_print(CCX_DMT_708, "C0: [%02X] (%d) [%s]\n",data[0],data_length, name);
ccx_common_logging.debug_ftn(CCX_DMT_708, "C0: [%02X] (%d) [%s]\n",data[0],data_length, name);
int len=-1;
// These commands have a known length even if they are reserved.
// These commands have a known length even if they are reserved.
if (/* data[0]>=0x00 && */ data[0]<=0xF) // Comment to silence warning
{
switch (data[0])
@@ -455,7 +472,7 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
process_cr (decoder);
break;
case 0x0e: // HCR (Horizontal Carriage Return)
// TODO: Process HDR
// TODO: Process HDR
break;
case 0x0c: // FF (Form Feed)
// TODO: Process FF
@@ -480,27 +497,27 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
}
if (len==-1)
{
dbg_print(CCX_DMT_708, "In handle_708_C0. Len == -1, this is not possible!");
ccx_common_logging.debug_ftn(CCX_DMT_708, "In handle_708_C0. Len == -1, this is not possible!");
return -1;
}
if (len>data_length)
{
dbg_print(CCX_DMT_708, "handle_708_C0, command is %d bytes long but we only have %d\n",len, data_length);
ccx_common_logging.debug_ftn(CCX_DMT_708, "handle_708_C0, command is %d bytes long but we only have %d\n",len, data_length);
return -1;
}
}
// TODO: Do something useful eventually
return len;
}
void process_character (cc708_service_decoder *decoder, unsigned char internal_char)
{
dbg_print(CCX_DMT_708, ">>> Process_character: %c [%02X] - Window: %d %s, Pen: %d:%d\n", internal_char, internal_char,
{
ccx_common_logging.debug_ftn(CCX_DMT_708, ">>> Process_character: %c [%02X] - Window: %d %s, Pen: %d:%d\n", internal_char, internal_char,
decoder->current_window,
(decoder->windows[decoder->current_window].is_defined?"[OK]":"[undefined]"),
decoder->current_window!=-1 ? decoder->windows[decoder->current_window].pen_row:-1,
decoder->current_window!=-1 ? decoder->windows[decoder->current_window].pen_column:-1
);
);
if (decoder->current_window==-1 ||
!decoder->windows[decoder->current_window].is_defined) // Writing to a non existing window, skipping
return;
@@ -541,7 +558,7 @@ void process_character (cc708_service_decoder *decoder, unsigned char internal_c
int handle_708_G0 (cc708_service_decoder *decoder, unsigned char *data, int data_length)
{
// TODO: Substitution of the music note character for the ASCII DEL character
dbg_print(CCX_DMT_708, "G0: [%02X] (%c)\n",data[0],data[0]);
ccx_common_logging.debug_ftn(CCX_DMT_708, "G0: [%02X] (%c)\n",data[0],data[0]);
unsigned char c=get_internal_from_G0 (data[0]);
process_character (decoder, c);
return 1;
@@ -550,7 +567,7 @@ int handle_708_G0 (cc708_service_decoder *decoder, unsigned char *data, int data
// G1 Code Set - ISO 8859-1 LATIN-1 Character Set
int handle_708_G1 (cc708_service_decoder *decoder, unsigned char *data, int data_length)
{
dbg_print(CCX_DMT_708, "G1: [%02X] (%c)\n",data[0],data[0]);
ccx_common_logging.debug_ftn(CCX_DMT_708, "G1: [%02X] (%c)\n",data[0],data[0]);
unsigned char c=get_internal_from_G1 (data[0]);
process_character (decoder, c);
return 1;
@@ -558,10 +575,10 @@ int handle_708_G1 (cc708_service_decoder *decoder, unsigned char *data, int data
/*-------------------------------------------------------
WINDOW COMMANDS
------------------------------------------------------- */
------------------------------------------------------- */
void handle_708_CWx_SetCurrentWindow (cc708_service_decoder *decoder, int new_window)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_CWx_SetCurrentWindow, new window: [%d]\n",new_window);
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_CWx_SetCurrentWindow, new window: [%d]\n",new_window);
if (decoder->windows[new_window].is_defined)
decoder->current_window=new_window;
}
@@ -574,29 +591,29 @@ void clearWindow (cc708_service_decoder *decoder, int window)
void handle_708_CLW_ClearWindows (cc708_service_decoder *decoder, int windows_bitmap)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_CLW_ClearWindows, windows: ");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_CLW_ClearWindows, windows: ");
if (windows_bitmap==0)
dbg_print(CCX_DMT_708, "None\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
else
{
for (int i=0; i<8; i++)
{
if (windows_bitmap & 1)
{
dbg_print(CCX_DMT_708, "[Window %d] ",i );
clearWindow (decoder, i);
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
clearWindow (decoder, i);
}
windows_bitmap>>=1;
}
}
dbg_print(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
}
void handle_708_DSW_DisplayWindows (cc708_service_decoder *decoder, int windows_bitmap)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_DSW_DisplayWindows, windows: ");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DSW_DisplayWindows, windows: ");
if (windows_bitmap==0)
dbg_print(CCX_DMT_708, "None\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
else
{
int changes=0;
@@ -604,26 +621,26 @@ void handle_708_DSW_DisplayWindows (cc708_service_decoder *decoder, int windows_
{
if (windows_bitmap & 1)
{
dbg_print(CCX_DMT_708, "[Window %d] ",i );
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
if (!decoder->windows[i].visible)
{
changes=1;
decoder->windows[i].visible=1;
}
}
}
windows_bitmap>>=1;
}
dbg_print(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
if (changes)
updateScreen (decoder);
}
}
}
void handle_708_HDW_HideWindows (cc708_service_decoder *decoder, int windows_bitmap)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_HDW_HideWindows, windows: ");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_HDW_HideWindows, windows: ");
if (windows_bitmap==0)
dbg_print(CCX_DMT_708, "None\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
else
{
int changes=0;
@@ -631,7 +648,7 @@ void handle_708_HDW_HideWindows (cc708_service_decoder *decoder, int windows_bit
{
if (windows_bitmap & 1)
{
dbg_print(CCX_DMT_708, "[Window %d] ",i );
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
if (decoder->windows[i].is_defined && decoder->windows[i].visible && !decoder->windows[i].is_empty)
{
changes=1;
@@ -641,31 +658,31 @@ void handle_708_HDW_HideWindows (cc708_service_decoder *decoder, int windows_bit
}
windows_bitmap>>=1;
}
dbg_print(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
if (changes)
updateScreen (decoder);
}
}
}
void handle_708_TGW_ToggleWindows (cc708_service_decoder *decoder, int windows_bitmap)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_TGW_ToggleWindows, windows: ");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_TGW_ToggleWindows, windows: ");
if (windows_bitmap==0)
dbg_print(CCX_DMT_708, "None\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
else
{
for (int i=0; i<8; i++)
{
if (windows_bitmap & 1)
{
dbg_print(CCX_DMT_708, "[Window %d] ",i );
decoder->windows[i].visible=!decoder->windows[i].visible;
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
decoder->windows[i].visible=!decoder->windows[i].visible;
}
windows_bitmap>>=1;
}
updateScreen(decoder);
}
dbg_print(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
}
void clearWindowText (e708Window *window)
@@ -682,14 +699,14 @@ void clearWindowText (e708Window *window)
void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, unsigned char *data)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_DFx_DefineWindow, window [%d], attributes: \n", window);
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DFx_DefineWindow, window [%d], attributes: \n", window);
if (decoder->windows[window].is_defined &&
memcmp (decoder->windows[window].commands, data+1, 6)==0)
{
// When a decoder receives a DefineWindow command for an existing window, the
// command is to be ignored if the command parameters are unchanged from the
// previous window definition.
dbg_print(CCX_DMT_708, " Repeated window definition, ignored.\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Repeated window definition, ignored.\n");
return;
}
decoder->windows[window].number=window;
@@ -702,16 +719,16 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
int anchor_horizontal = data[3];
int row_count = data[4] & 0xf;
int anchor_point = data[4]>>4;
int col_count = data[5] & 0x3f;
int col_count = data[5] & 0x3f;
int pen_style = data[6] & 0x7;
int win_style = (data[6]>>3) & 0x7;
dbg_print(CCX_DMT_708, " Priority: [%d] Column lock: [%3s] Row lock: [%3s]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Priority: [%d] Column lock: [%3s] Row lock: [%3s]\n",
priority, col_lock?"Yes": "No", row_lock?"Yes": "No");
dbg_print(CCX_DMT_708, " Visible: [%3s] Anchor vertical: [%2d] Relative pos: [%s]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Visible: [%3s] Anchor vertical: [%2d] Relative pos: [%s]\n",
visible?"Yes": "No", anchor_vertical, relative_pos?"Yes": "No");
dbg_print(CCX_DMT_708, " Anchor horizontal: [%3d] Row count: [%2d]+1 Anchor point: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Anchor horizontal: [%3d] Row count: [%2d]+1 Anchor point: [%d]\n",
anchor_horizontal, row_count, anchor_point);
dbg_print(CCX_DMT_708, " Column count: [%2d]1 Pen style: [%d] Win style: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Column count: [%2d]1 Pen style: [%d] Win style: [%d]\n",
col_count, pen_style, win_style);
col_count++; // These increments seems to be needed but no documentation
row_count++; // backs it up
@@ -732,7 +749,7 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
// If the window is being created, all character positions in the window
// are set to the fill color...
// TODO: COLORS
// ...and the pen location is set to (0,0)
// ...and the pen location is set to (0,0)
decoder->windows[window].pen_column=0;
decoder->windows[window].pen_row=0;
if (!decoder->windows[window].memory_reserved)
@@ -742,13 +759,13 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
decoder->windows[window].rows[i]=(unsigned char *) malloc (I708_MAX_COLUMNS+1);
if (decoder->windows[window].rows[i]==NULL) // Great
{
decoder->windows[window].is_defined=0;
decoder->windows[window].is_defined=0;
decoder->current_window=-1;
for (int j=0;j<i;j++)
for (int j=0;j<i;j++)
free (decoder->windows[window].rows[j]);
return; // TODO: Warn somehow
}
}
}
decoder->windows[window].memory_reserved=1;
}
decoder->windows[window].is_defined=1;
@@ -759,7 +776,7 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
// Specs unclear here: Do we need to delete the text in the existing window?
// We do this because one of the sample files demands it.
// clearWindowText (&decoder->windows[window]);
}
}
// ...also makes the defined windows the current window (setCurrentWindow)
handle_708_CWx_SetCurrentWindow (decoder, window);
memcpy (decoder->windows[window].commands, data+1, 6);
@@ -767,7 +784,7 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
void handle_708_SWA_SetWindowAttributes (cc708_service_decoder *decoder, unsigned char *data)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_SWA_SetWindowAttributes, attributes: \n");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_SWA_SetWindowAttributes, attributes: \n");
int fill_color = (data[1] ) & 0x3f;
int fill_opacity = (data[1]>>6) & 0x03;
int border_color = (data[2] ) & 0x3f;
@@ -780,11 +797,11 @@ void handle_708_SWA_SetWindowAttributes (cc708_service_decoder *decoder, unsigne
int display_eff = (data[4] ) & 0x03;
int effect_dir = (data[4]>>2) & 0x03;
int effect_speed = (data[4]>>4) & 0x0f;
dbg_print(CCX_DMT_708, " Fill color: [%d] Fill opacity: [%d] Border color: [%d] Border type: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Fill color: [%d] Fill opacity: [%d] Border color: [%d] Border type: [%d]\n",
fill_color, fill_opacity, border_color, border_type01);
dbg_print(CCX_DMT_708, " Justify: [%d] Scroll dir: [%d] Print dir: [%d] Word wrap: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Justify: [%d] Scroll dir: [%d] Print dir: [%d] Word wrap: [%d]\n",
justify, scroll_dir, print_dir, word_wrap);
dbg_print(CCX_DMT_708, " Border type: [%d] Display eff: [%d] Effect dir: [%d] Effect speed: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Border type: [%d] Display eff: [%d] Effect dir: [%d] Effect speed: [%d]\n",
border_type, display_eff, effect_dir, effect_speed);
if (decoder->current_window==-1)
{
@@ -827,16 +844,16 @@ void deleteWindow (cc708_service_decoder *decoder, int window)
void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_bitmap)
{
int changes=0;
dbg_print(CCX_DMT_708, " Entry in handle_708_DLW_DeleteWindows, windows: ");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DLW_DeleteWindows, windows: ");
if (windows_bitmap==0)
dbg_print(CCX_DMT_708, "None\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
else
{
for (int i=0; i<8; i++)
{
if (windows_bitmap & 1)
{
dbg_print(CCX_DMT_708, "[Window %d] ",i );
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
if (decoder->windows[i].is_defined && decoder->windows[i].visible && !decoder->windows[i].is_empty)
changes=1;
deleteWindow (decoder, i);
@@ -844,7 +861,7 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
windows_bitmap>>=1;
}
}
dbg_print(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
if (changes)
updateScreen (decoder);
@@ -852,10 +869,10 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
/*-------------------------------------------------------
WINDOW COMMANDS
------------------------------------------------------- */
------------------------------------------------------- */
void handle_708_SPA_SetPenAttributes (cc708_service_decoder *decoder, unsigned char *data)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_SPA_SetPenAttributes, attributes: \n");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_SPA_SetPenAttributes, attributes: \n");
int pen_size = (data[1] ) & 0x3;
int offset = (data[1]>>2) & 0x3;
int text_tag = (data[1]>>4) & 0xf;
@@ -863,10 +880,10 @@ void handle_708_SPA_SetPenAttributes (cc708_service_decoder *decoder, unsigned c
int edge_type = (data[2]>>3) & 0x7;
int underline = (data[2]>>4) & 0x1;
int italic = (data[2]>>5) & 0x1;
dbg_print(CCX_DMT_708, " Pen size: [%d] Offset: [%d] Text tag: [%d] Font tag: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Pen size: [%d] Offset: [%d] Text tag: [%d] Font tag: [%d]\n",
pen_size, offset, text_tag, font_tag);
dbg_print(CCX_DMT_708, " Edge type: [%d] Underline: [%d] Italic: [%d]\n",
edge_type, underline, italic);
ccx_common_logging.debug_ftn(CCX_DMT_708, " Edge type: [%d] Underline: [%d] Italic: [%d]\n",
edge_type, underline, italic);
if (decoder->current_window==-1)
{
// Can't do anything yet - we need a window to be defined first.
@@ -883,17 +900,17 @@ void handle_708_SPA_SetPenAttributes (cc708_service_decoder *decoder, unsigned c
void handle_708_SPC_SetPenColor (cc708_service_decoder *decoder, unsigned char *data)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_SPC_SetPenColor, attributes: \n");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_SPC_SetPenColor, attributes: \n");
int fg_color = (data[1] ) & 0x3f;
int fg_opacity = (data[1]>>6) & 0x03;
int bg_color = (data[2] ) & 0x3f;
int bg_opacity = (data[2]>>6) & 0x03;
int edge_color = (data[3]>>6) & 0x3f;
dbg_print(CCX_DMT_708, " Foreground color: [%d] Foreground opacity: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Foreground color: [%d] Foreground opacity: [%d]\n",
fg_color, fg_opacity);
dbg_print(CCX_DMT_708, " Background color: [%d] Background opacity: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Background color: [%d] Background opacity: [%d]\n",
bg_color, bg_opacity);
dbg_print(CCX_DMT_708, " Edge color: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " Edge color: [%d]\n",
edge_color);
if (decoder->current_window==-1)
{
@@ -911,10 +928,10 @@ void handle_708_SPC_SetPenColor (cc708_service_decoder *decoder, unsigned char *
void handle_708_SPL_SetPenLocation (cc708_service_decoder *decoder, unsigned char *data)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_SPL_SetPenLocation, attributes: \n");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_SPL_SetPenLocation, attributes: \n");
int row = data[1] & 0x0f;
int col = data[2] & 0x3f;
dbg_print(CCX_DMT_708, " row: [%d] Column: [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, " row: [%d] Column: [%d]\n",
row, col);
if (decoder->current_window==-1)
{
@@ -928,17 +945,17 @@ void handle_708_SPL_SetPenLocation (cc708_service_decoder *decoder, unsigned cha
/*-------------------------------------------------------
SYNCHRONIZATION COMMANDS
------------------------------------------------------- */
------------------------------------------------------- */
void handle_708_DLY_Delay (cc708_service_decoder *decoder, int tenths_of_sec)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_DLY_Delay, delay for [%d] tenths of second.", tenths_of_sec);
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DLY_Delay, delay for [%d] tenths of second.", tenths_of_sec);
// TODO: Probably ask for the current FTS and wait for this time before resuming -
// not sure it's worth it though
}
void handle_708_DLC_DelayCancel (cc708_service_decoder *decoder)
{
dbg_print(CCX_DMT_708, " Entry in handle_708_DLC_DelayCancel.");
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DLC_DelayCancel.");
// TODO: See above
}
@@ -946,12 +963,12 @@ void handle_708_DLC_DelayCancel (cc708_service_decoder *decoder)
int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data_length)
{
struct S_COMMANDS_C1 com=COMMANDS_C1[data[0]-0x80];
dbg_print(CCX_DMT_708, "%s | C1: [%02X] [%s] [%s] (%d)\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, "%s | C1: [%02X] [%s] [%s] (%d)\n",
print_mstime(get_fts()),
data[0],com.name,com.description, com.length);
data[0],com.name,com.description, com.length);
if (com.length>data_length)
{
dbg_print(CCX_DMT_708, "C1: Warning: Not enough bytes for command.\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "C1: Warning: Not enough bytes for command.\n");
return -1;
}
switch (com.code)
@@ -967,7 +984,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
handle_708_CWx_SetCurrentWindow (decoder, com.code-CW0); /* Window 0 to 7 */
break;
case CLW:
handle_708_CLW_ClearWindows (decoder, data[1]);
handle_708_CLW_ClearWindows (decoder, data[1]);
break;
case DSW:
handle_708_DSW_DisplayWindows (decoder, data[1]);
@@ -998,16 +1015,16 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
break;
case SPL:
handle_708_SPL_SetPenLocation (decoder, data);
break;
break;
case RSV93:
case RSV94:
case RSV95:
case RSV96:
dbg_print(CCX_DMT_708, "Warning, found Reserved codes, ignored.\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning, found Reserved codes, ignored.\n");
break;
case SWA:
handle_708_SWA_SetWindowAttributes (decoder, data);
break;
break;
case DF0:
case DF1:
case DF2:
@@ -1017,23 +1034,23 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
case DF6:
case DF7:
handle_708_DFx_DefineWindow (decoder, com.code-DF0, data); /* Window 0 to 7 */
break;
break;
default:
mprint ("BUG: Unhandled code in handle_708_C1.\n");
break;
ccx_common_logging.log_ftn ("BUG: Unhandled code in handle_708_C1.\n");
break;
}
return com.length;
}
void process_service_block (cc708_service_decoder *decoder, unsigned char *data, int data_length)
{
int i=0;
int i=0;
while (i<data_length)
{
int used=-1;
if (data[i]!=EXT1)
if (data[i]!=EXT1)
{
// Group C0
if (/* data[i]>=0x00 && */ data[i]<=0x1F) // Comment to silence warning
@@ -1055,142 +1072,143 @@ void process_service_block (cc708_service_decoder *decoder, unsigned char *data,
used=handle_708_G1 (decoder,data+i,data_length-i);
if (used==-1)
{
dbg_print(CCX_DMT_708, "There was a problem handling the data. Reseting service decoder\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "There was a problem handling the data. Reseting service decoder\n");
// TODO: Not sure if a local reset is going to be helpful here.
cc708_service_reset (decoder);
return;
return;
}
}
else // Use extended set
{
{
used=handle_708_extended_char (decoder, data+i+1,data_length-1);
used++; // Since we had EXT1
used++; // Since we had EXT1
}
i+=used;
i+=used;
}
}
void process_current_packet (void)
void process_current_packet (struct lib_cc_decode* ctx)
{
int seq=(current_packet[0] & 0xC0) >> 6; // Two most significants bits
int len=current_packet[0] & 0x3F; // 6 least significants bits
#ifdef DEBUG_708_PACKETS
mprint ("Processing EIA-708 packet, length=%d, seq=%d\n",current_packet_length, seq);
ccx_common_logging.log_ftn ("Processing EIA-708 packet, length=%d, seq=%d\n",current_packet_length, seq);
#endif
if (current_packet_length==0)
return;
if (len==0) // This is well defined in EIA-708; no magic.
len=128;
len=128;
else
len=len*2;
// Note that len here is the length including the header
#ifdef DEBUG_708_PACKETS
mprint ("Sequence: %d, packet length: %d\n",seq,len);
#ifdef DEBUG_708_PACKETS
ccx_common_logging.log_ftn ("Sequence: %d, packet length: %d\n",seq,len);
#endif
if (current_packet_length!=len) // Is this possible?
{
dbg_print(CCX_DMT_708, "Packet length mismatch (%s%d), first two data bytes %02X %02X, current picture:%s\n",
current_packet_length-len>0?"+":"", current_packet_length-len,
ccx_common_logging.debug_ftn(CCX_DMT_708, "Packet length mismatch (%s%d), first two data bytes %02X %02X, current picture:%s\n",
current_packet_length-len>0?"+":"", current_packet_length-len,
current_packet[0], current_packet[1], pict_types[current_picture_coding_type]);
cc708_reset();
cc708_reset(ctx);
return;
}
if (last_seq!=-1 && (last_seq+1)%4!=seq)
{
dbg_print(CCX_DMT_708, "Unexpected sequence number, it was [%d] but should have been [%d]\n",
ccx_common_logging.debug_ftn(CCX_DMT_708, "Unexpected sequence number, it was [%d] but should have been [%d]\n",
seq,(last_seq+1)%4);
cc708_reset();
cc708_reset(ctx);
return;
}
last_seq=seq;
unsigned char *pos=current_packet+1;
unsigned char *pos=current_packet+1;
while (pos<current_packet+len)
{
int service_number=(pos[0] & 0xE0)>>5; // 3 more significant bits
int block_length = (pos[0] & 0x1F); // 5 less significant bits
dbg_print (CCX_DMT_708, "Standard header: Service number: [%d] Block length: [%d]\n",service_number,
block_length);
ccx_common_logging.debug_ftn (CCX_DMT_708, "Standard header: Service number: [%d] Block length: [%d]\n",service_number,
block_length);
if (service_number==7) // There is an extended header
{
pos++;
pos++;
service_number=(pos[0] & 0x3F); // 6 more significant bits
// printf ("Extended header: Service number: [%d]\n",service_number);
if (service_number<7)
if (service_number<7)
{
dbg_print(CCX_DMT_708, "Illegal service number in extended header: [%d]\n",service_number);
ccx_common_logging.debug_ftn(CCX_DMT_708, "Illegal service number in extended header: [%d]\n",service_number);
}
}
}
/*
if (service_number==0 && block_length==0) // Null header already?
{
if (pos!=(current_packet+len-1)) // i.e. last byte in packet
{
// Not sure if this is correct
printf ("Null header before it was expected.\n");
printf ("Null header before it was expected.\n");
// break;
}
} */
pos++; // Move to service data
if (service_number==0 && block_length!=0) // Illegal, but specs say what to do...
{
dbg_print(CCX_DMT_708, "Data received for service 0, skipping rest of packet.");
ccx_common_logging.debug_ftn(CCX_DMT_708, "Data received for service 0, skipping rest of packet.");
pos = current_packet+len; // Move to end
break;
}
if (block_length != 0)
file_report.services708[service_number] = 1;
if (block_length != 0){
ccx_decoder_708_report.services[service_number] = 1;
}
if (service_number>0 && decoders[service_number-1].inited)
process_service_block (&decoders[service_number-1], pos, block_length);
pos+=block_length; // Skip data
pos+=block_length; // Skip data
}
clear_packet();
if (pos!=current_packet+len) // For some reason we didn't parse the whole packet
{
dbg_print(CCX_DMT_708, "There was a problem with this packet, reseting\n");
cc708_reset();
ccx_common_logging.debug_ftn(CCX_DMT_708, "There was a problem with this packet, reseting\n");
cc708_reset(ctx);
}
if (len<128 && *pos) // Null header is mandatory if there is room
{
dbg_print(CCX_DMT_708, "Warning: Null header expected but not found.\n");
}
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Null header expected but not found.\n");
}
}
void do_708 (const unsigned char *data, int datalength)
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength)
{
/* Note: The data has this format:
1 byte for cc_valid
/* Note: The data has this format:
1 byte for cc_valid
1 byte for cc_type
2 bytes for the actual data */
if (!do_cea708 && !ccx_options.print_file_reports)
if (!do_cea708 && !ccx_decoders_708_report)
return;
for (int i=0;i<datalength;i+=4)
{
unsigned char cc_valid=data[i];
unsigned char cc_type=data[i+1];
unsigned char cc_type=data[i+1];
switch (cc_type)
{
case 2:
dbg_print (CCX_DMT_708, "708: DTVCC Channel Packet Data\n");
case 2:
ccx_common_logging.debug_ftn (CCX_DMT_708, "708: DTVCC Channel Packet Data\n");
if (cc_valid==0) // This ends the previous packet
process_current_packet();
process_current_packet(ctx);
else
{
if (current_packet_length>253)
if (current_packet_length>253)
{
dbg_print(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
}
else
{
@@ -1199,14 +1217,14 @@ void do_708 (const unsigned char *data, int datalength)
}
}
break;
case 3:
dbg_print (CCX_DMT_708, "708: DTVCC Channel Packet Start\n");
process_current_packet();
case 3:
ccx_common_logging.debug_ftn (CCX_DMT_708, "708: DTVCC Channel Packet Start\n");
process_current_packet(ctx);
if (cc_valid)
{
if (current_packet_length>253)
if (current_packet_length>127)
{
dbg_print(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
}
else
{
@@ -1215,25 +1233,26 @@ void do_708 (const unsigned char *data, int datalength)
}
}
break;
default:
fatal (EXIT_BUG_BUG, "708: shouldn't be here - cc_type: %d\n", cc_type);
default:
ccx_common_logging.fatal_ftn (CCX_COMMON_EXIT_BUG_BUG, "708: shouldn't be here - cc_type: %d\n", cc_type);
}
}
}
void init_708(void)
void ccx_decoders_708_init_library(char *basefilename,const char *extension,int report)
{
for (int i=0;i<63;i++)
for (int i = 0; i<CCX_DECODERS_708_MAX_SERVICES; i++)
{
if (!cea708services[i])
continue;
cc708_service_reset (&decoders[i]);
if (decoders[i].filename==NULL)
{
decoders[i].filename = (char *) malloc (strlen (basefilename)+4+strlen (extension));
sprintf (decoders[i].filename, "%s_%d%s", basefilename,i+1,extension);
}
decoders[i].filename = (char *) malloc (strlen (basefilename)+4+strlen (extension));
sprintf (decoders[i].filename, "%s_%d%s", basefilename,i+1,extension);
}
decoders[i].fh=-1;
decoders[i].srt_counter=0;
}
}
ccx_decoders_708_report = report;
}

View File

@@ -1,15 +1,31 @@
#ifndef _INCLUDE_708_
#define _INCLUDE_708_
#include <sys/stat.h>
#include "ccx_decoders_common.h"
#define MAX_708_PACKET_LENGTH 128
#define CCX_DECODERS_708_MAX_SERVICES 63
#define I708_MAX_ROWS 15
#define I708_MAX_COLUMNS 42
#define I708_MAX_COLUMNS 42
#define I708_SCREENGRID_ROWS 75
#define I708_SCREENGRID_COLUMNS 210
#define I708_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
{
unsigned services[CCX_DECODERS_708_MAX_SERVICES];
};
extern struct ccx_decoder_708_report_t ccx_decoder_708_report;
enum COMMANDS_C0_CODES
{
NUL=0,
@@ -40,7 +56,7 @@ enum COMMANDS_C1_CODES
DLY=0x8D,
DLC=0x8E,
RST=0x8F,
SPA=0x90,
SPA=0x90,
SPC=0x91,
SPL=0x92,
RSV93=0x93,
@@ -259,7 +275,7 @@ typedef struct e708Window
typedef struct tvscreen
{
unsigned char chars[I708_SCREENGRID_ROWS][I708_SCREENGRID_COLUMNS+1];
}
}
tvscreen;
typedef struct cc708_service_decoder
@@ -275,13 +291,17 @@ typedef struct cc708_service_decoder
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;
extern int do_cea708; // Process 708 data?
extern int cea708services[]; // [] -> 1 for services to be processed
extern int resets_708;
void do_708 (const unsigned char *data, int datalength);
void init_708(void);
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength);
unsigned char get_internal_from_G0 (unsigned char g0_char);
unsigned char get_internal_from_G1 (unsigned char g1_char);
@@ -289,4 +309,5 @@ 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);
void ccx_decoders_708_init_library(char *basefilename,const char *extension, int report);
#endif

View File

@@ -0,0 +1,319 @@
/* Functions used by both the 608 and 708 decoders. An effort should be
made to reuse, not duplicate, as many functions as possible */
#include "ccx_decoders_common.h"
#include "ccx_common_structs.h"
#include "ccx_common_char_encoding.h"
#include "ccx_common_constants.h"
#include "ccx_common_timing.h"
#include "ccx_common_common.h"
#include "lib_ccx.h"
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 fts = get_fts();
if (fts <= minimum_fts)
fts = 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)
{
LLONG fts = get_fts();
if (fts>minimum_fts)
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;
for (int j = 0; j < cc_count * 3; j = j + 3)
{
if (validate_cc_data_pair( cc_data + j ) )
continue;
ret = do_cb(ctx, cc_data + j, sub);
if (ret == 1) //1 means success here
ret = 0;
}
return ret;
}
int validate_cc_data_pair (unsigned char *cc_data_pair)
{
unsigned char cc_valid = (*cc_data_pair & 4) >>2;
unsigned char cc_type = *cc_data_pair & 3;
if (!cc_valid)
return -1;
if (cc_type==0 || cc_type==1)
{
// For EIA-608 data we verify parity.
if (!cc608_parity_table[cc_data_pair[2]])
{
// If the second byte doesn't pass parity, ignore pair
return -1;
}
if (!cc608_parity_table[cc_data_pair[1]])
{
// The first byte doesn't pass parity, we replace it with a solid blank
// and process the pair.
cc_data_pair[1]=0x7F;
}
}
return 0;
}
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub)
{
unsigned char cc_valid = (*cc_block & 4) >>2;
unsigned char cc_type = *cc_block & 3;
int timeok = 1;
if ( ctx->fix_padding
&& cc_valid==0 && cc_type <= 1 // Only fix NTSC packets
&& cc_block[1]==0 && cc_block[2]==0 )
{
/* Padding */
cc_valid=1;
cc_block[1]=0x80;
cc_block[2]=0x80;
}
if ( ctx->write_format!=CCX_OF_RAW && // In raw we cannot skip padding because timing depends on it
ctx->write_format!=CCX_OF_DVDRAW &&
(cc_block[0]==0xFA || cc_block[0]==0xFC || cc_block[0]==0xFD )
&& (cc_block[1]&0x7F)==0 && (cc_block[2]&0x7F)==0) // CFS: Skip non-data, makes debugging harder.
return 1;
// Print raw data with FTS.
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(fts_now + fts_global),in_xds_mode,
cc_block[0], cc_block[1]&0x7f,cc_block[2]&0x7f, cc_block[2]);
/* In theory the writercwtdata() function could return early and not
* go through the 608/708 cases below. We do that to get accurate
* counts for cb_field1, cb_field2 and cb_708.
* Note that printdata() and do_708() must not be called for
* the CCX_OF_RCWT case. */
if (cc_valid || cc_type==3)
{
ctx->cc_stats[cc_type]++;
switch (cc_type)
{
case 0:
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
current_field=1;
ctx->saw_caption_block = 1;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
printdata (ctx, cc_block+1,2,0,0, sub);
else
writercwtdata(ctx, cc_block);
}
cb_field1++;
break;
case 1:
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
current_field=2;
ctx->saw_caption_block = 1;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
printdata (ctx, 0,0,cc_block+1,2, sub);
else
writercwtdata(ctx, cc_block);
}
cb_field2++;
break;
case 2: //EIA-708
// DTVCC packet data
// Fall through
case 3: //EIA-708
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
// DTVCC packet start
current_field=3;
if (ctx->extraction_start.set &&
get_fts() < ctx->extraction_start.time_in_ms)
timeok = 0;
if (ctx->extraction_end.set &&
get_fts() > ctx->extraction_end.time_in_ms)
{
timeok = 0;
ctx->processed_enough=1;
}
char temp[4];
temp[0]=cc_valid;
temp[1]=cc_type;
temp[2]=cc_block[1];
temp[3]=cc_block[2];
if (timeok)
{
if(ctx->write_format!=CCX_OF_RCWT)
do_708 (ctx,(const unsigned char *) temp, 4);
else
writercwtdata(ctx, cc_block);
}
cb_708++;
// Check for bytes read
// printf ("Warning: Losing EIA-708 data!\n");
break;
default:
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
} // switch (cc_type)
} // cc_valid
else
{
dbg_print(CCX_DMT_CBRAW, " .. .. ..\n");
dbg_print(CCX_DMT_VERBOSE, "Found !(cc_valid || cc_type==3) - ignore this block\n");
}
return 1;
}
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting)
{
struct lib_cc_decode *ctx = NULL;
ctx = malloc(sizeof(struct lib_cc_decode));
if(!ctx)
return NULL;
// Prepare 608 context
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
ccx_options.settings_608,
ccx_options.cc_channel,
1,
ccx_options.trim_subs,
ccx_options.encoding,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->subs_delay,
setting->output_format
);
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
ccx_options.settings_608,
ccx_options.cc_channel,
2,
ccx_options.trim_subs,
ccx_options.encoding,
&ctx->processed_enough,
setting->cc_to_stdout,
setting->subs_delay,
setting->output_format
);
ctx->fix_padding = setting->fix_padding;
ctx->write_format = setting->output_format;
ctx->subs_delay = setting->subs_delay;
ctx->wbout1 = setting->wbout1;
memcpy(&ctx->extraction_start, &setting->extraction_start,sizeof(struct ccx_boundary_time));
memcpy(&ctx->extraction_end, &setting->extraction_end,sizeof(struct ccx_boundary_time));
return ctx;
}
void dinit_cc_decode(struct lib_cc_decode **ctx)
{
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);
}

View File

@@ -0,0 +1,34 @@
#ifndef _CC_DECODER_COMMON
#define _CC_DECODER_COMMON
#include "ccx_common_platform.h"
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
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);
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);
void ccx_decoders_common_settings_init(LLONG subs_delay, enum ccx_output_format output_format);
int validate_cc_data_pair (unsigned char *cc_data_pair);
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub);
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub);
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
const unsigned char *data2, int length2, struct cc_subtitle *sub);
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting);
void dinit_cc_decode(struct lib_cc_decode **ctx);
#endif

View File

@@ -0,0 +1,106 @@
#ifndef CCX_DECODERS_STRUCTS_H
#define CCX_DECODERS_STRUCTS_H
#include "ccx_common_platform.h"
#include "ccx_common_constants.h"
#include "ccx_common_timing.h"
// Define max width in characters/columns on the screen
#define CCX_DECODER_608_SCREEN_WIDTH 32
/* flag raised when end of display marker arrives in Dvb Subtitle */
#define SUB_EOD_MARKER (1 << 0 )
struct cc_bitmap
{
int x;
int y;
int w;
int h;
int nb_colors;
unsigned char *data[2];
int linesize[2];
#ifdef ENABLE_OCR
char *ocr_text;
#endif
};
enum ccx_eia608_format
{
SFORMAT_CC_SCREEN,
SFORMAT_CC_LINE,
SFORMAT_XDS
};
enum cc_modes
{
MODE_POPON = 0,
MODE_ROLLUP_2 = 1,
MODE_ROLLUP_3 = 2,
MODE_ROLLUP_4 = 3,
MODE_TEXT = 4,
MODE_PAINTON = 5,
// Fake modes to emulate stuff
MODE_FAKE_ROLLUP_1 = 100
};
/**
* This structure have fields which need to be ignored according to format,
* for example if format is SFORMAT_XDS then all fields other then
* xds related (xds_str, xds_len and cur_xds_packet_class) should be
* ignored and not to be derefrenced.
*
* TODO use union inside struct for each kind of fields
*/
typedef struct eia608_screen // A CC buffer
{
/** format of data inside this structure */
enum ccx_eia608_format format;
unsigned char characters[15][33];
unsigned char colors[15][33];
unsigned char fonts[15][33]; // Extra char at the end for a 0
int row_used[15]; // Any data in row?
int empty; // Buffer completely empty?
/** start time of this CC buffer */
LLONG start_time;
/** end time of this CC buffer */
LLONG end_time;
enum cc_modes mode;
int channel; // Currently selected channel
int my_field; // Used for sanity checks
/** XDS string */
char *xds_str;
/** length of XDS string */
size_t xds_len;
/** Class of XDS string */
int cur_xds_packet_class;
} eia608_screen;
struct ccx_decoders_common_settings_t
{
LLONG subs_delay; // ms to delay (or advance) subs
enum ccx_output_format output_format; // What kind of output format should be used?
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
void *wbout1;
int cc_to_stdout;
};
struct lib_cc_decode
{
int cc_stats[4];
int saw_caption_block;
int processed_enough; // If 1, we have enough lines, time, etc.
/* 608 contexts - note that this shouldn't be global, they should be
per program */
void *context_cc608_field_1;
void *context_cc608_field_2;
int 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
};
#endif

View File

@@ -1,4 +1,14 @@
#include "ccextractor.h"
#include "ccx_decoders_xds.h"
#include "ccx_common_constants.h"
#include "ccx_common_timing.h"
LLONG ts_start_of_xds = -1; // Time at which we switched to XDS mode, =-1 hasn't happened yet
struct ccx_decoders_xds_context_t {
ccx_encoders_transcript_format transcriptFormat;
LLONG subsDelay;
char millisSeparator;
} ccx_decoders_xds_context;
// Program Identification Number (Start Time) for current program
static int current_xds_min=-1;
@@ -10,8 +20,8 @@ static int xds_start_time_shown=0;
static int xds_program_length_shown=0;
static char xds_program_description[8][33];
static char current_xds_network_name[33];
static char current_xds_program_name[33];
static char current_xds_network_name[33];
static char current_xds_program_name[33];
static char current_xds_call_letters[7];
static char current_xds_program_type[33];
@@ -71,6 +81,7 @@ static const char *XDSProgramTypes[]=
#define XDS_CLASS_RESERVED 5
#define XDS_CLASS_PRIVATE 6
#define XDS_CLASS_END 7
#define XDS_CLASS_OUT_OF_BAND 0x40 // Not a real class, a marker for packets for out-of-band data.
// Types for the classes current and future
#define XDS_TYPE_PIN_START_TIME 1
@@ -90,13 +101,14 @@ static const char *XDSProgramTypes[]=
#define XDS_TYPE_PROGRAM_DESC_8 0x17
// Types for the class channel
#define XDS_TYPE_NETWORK_NAME 1
#define XDS_TYPE_CALL_LETTERS_AND_CHANNEL 2
#define XDS_TYPE_NETWORK_NAME 1
#define XDS_TYPE_CALL_LETTERS_AND_CHANNEL 2
#define XDS_TYPE_TSID 4 // Transmission Signal Identifier
// Types for miscellaneous packets
#define XDS_TYPE_TIME_OF_DAY 1
#define XDS_TYPE_TIME_OF_DAY 1
#define XDS_TYPE_LOCAL_TIME_ZONE 4
#define XDS_TYPE_OUT_OF_BAND_CHANNEL_NUMBER 0x40
#define NUM_XDS_BUFFERS 9 // CEA recommends no more than one level of interleaving. Play it safe
#define NUM_BYTES_PER_PACKET 35 // Class + type (repeated for convenience) + data + zero
@@ -108,7 +120,7 @@ struct xds_buffer
int xds_type;
unsigned char bytes[NUM_BYTES_PER_PACKET]; // Class + type (repeated for convenience) + data + zero
unsigned char used_bytes;
} xds_buffers[NUM_XDS_BUFFERS];
} xds_buffers[NUM_XDS_BUFFERS];
static int cur_xds_buffer_idx=-1;
static int cur_xds_packet_class=-1;
@@ -116,26 +128,60 @@ static unsigned char *cur_xds_payload;
static int cur_xds_payload_length;
static int cur_xds_packet_type;
void xds_init()
void ccx_decoders_xds_init_library(ccx_encoders_transcript_format *transcriptSettings, LLONG subs_delay, char millis_separator)
{
for (int i=0;i<NUM_XDS_BUFFERS;i++)
ccx_decoders_xds_context.transcriptFormat = *transcriptSettings;
ccx_decoders_xds_context.subsDelay = subs_delay;
ccx_decoders_xds_context.millisSeparator = millis_separator;
for (int i = 0; i<NUM_XDS_BUFFERS; i++)
{
xds_buffers[i].in_use=0;
xds_buffers[i].xds_class=-1;
xds_buffers[i].xds_type=-1;
xds_buffers[i].used_bytes=0;
memset (xds_buffers[i].bytes , 0, NUM_BYTES_PER_PACKET);
xds_buffers[i].in_use = 0;
xds_buffers[i].xds_class = -1;
xds_buffers[i].xds_type = -1;
xds_buffers[i].used_bytes = 0;
memset(xds_buffers[i].bytes, 0, NUM_BYTES_PER_PACKET);
}
for (int i=0; i<9; i++)
memset (xds_program_description,0,32);
memset (current_xds_network_name,0,33);
memset (current_xds_program_name,0,33);
memset (current_xds_call_letters,0,7);
memset (current_xds_program_type,0,33);
for (int i = 0; i<9; i++)
memset(xds_program_description, 0, 32);
memset(current_xds_network_name, 0, 33);
memset(current_xds_program_name, 0, 33);
memset(current_xds_call_letters, 0, 7);
memset(current_xds_program_type, 0, 33);
}
int write_xds_string(struct cc_subtitle *sub,char *p,size_t len)
{
struct eia608_screen *data = NULL;
data = (struct eia608_screen *) realloc(sub->data,( sub->nb_data + 1 ) * sizeof(*data));
if (!data)
{
freep(&sub->data);
sub->nb_data = 0;
ccx_common_logging.log_ftn("No Memory left");
return -1;
}
else
{
sub->data = data;
data = (struct eia608_screen *)sub->data + sub->nb_data;
data->format = SFORMAT_XDS;
data->start_time = ts_start_of_xds;
data->end_time = get_fts();
data->xds_str = p;
data->xds_len = len;
data->cur_xds_packet_class = cur_xds_packet_class;
sub->nb_data++;
sub->type = CC_608;
sub->got_output = 1;
}
return 0;
}
void xds_write_transcript_line_suffix (struct ccx_s_write *wb)
{
if (!wb || wb->fh==-1)
@@ -143,81 +189,75 @@ void xds_write_transcript_line_suffix (struct ccx_s_write *wb)
write (wb->fh, encoded_crlf, encoded_crlf_length);
}
void xds_write_transcript_line_prefix (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)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
if (!wb || wb->fh==-1)
return;
if (ts_start_of_xds == -1)
if (start_time == -1)
{
// Means we entered XDS mode without making a note of the XDS start time. This is a bug.
fatal (EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
;
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
}
if (ccx_options.transcript_settings.showStartTime){
if (ccx_decoders_xds_context.transcriptFormat.showStartTime){
char buffer[80];
if (ccx_options.transcript_settings.relativeTimestamp){
if (ccx_decoders_xds_context.transcriptFormat.relativeTimestamp){
if (utc_refvalue == UINT64_MAX)
{
mstotime(ts_start_of_xds + subs_delay, &h1, &m1, &s1, &ms1);
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h1, m1, s1, ccx_options.millis_separator, ms1);
mstotime(start_time + ccx_decoders_xds_context.subsDelay, &h1, &m1, &s1, &ms1);
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h1, m1, s1, ccx_decoders_xds_context.millisSeparator, ms1);
}
else {
fdprintf(wb->fh, "%lld%c%03d|", (ts_start_of_xds + subs_delay) / 1000, ccx_options.millis_separator, (ts_start_of_xds + subs_delay) % 1000);
fdprintf(wb->fh, "%lld%c%03d|", (start_time + ccx_decoders_xds_context.subsDelay) / 1000, ccx_decoders_xds_context.millisSeparator, (start_time + ccx_decoders_xds_context.subsDelay) % 1000);
}
}
else {
mstotime(ts_start_of_xds + subs_delay, &h1, &m1, &s1, &ms1);
time_t start_time_int = (ts_start_of_xds + subs_delay) / 1000;
int start_time_dec = (ts_start_of_xds + subs_delay) % 1000;
mstotime(start_time + ccx_decoders_xds_context.subsDelay, &h1, &m1, &s1, &ms1);
time_t start_time_int = (start_time + ccx_decoders_xds_context.subsDelay) / 1000;
int start_time_dec = (start_time + ccx_decoders_xds_context.subsDelay) % 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,ccx_options.millis_separator,start_time_dec);
fdprintf(wb->fh, "%s%c%03d|", buffer, ccx_decoders_xds_context.millisSeparator, start_time_dec);
}
}
if (ccx_options.transcript_settings.showEndTime){
if (ccx_decoders_xds_context.transcriptFormat.showEndTime){
char buffer[80];
if (ccx_options.transcript_settings.relativeTimestamp){
if (ccx_decoders_xds_context.transcriptFormat.relativeTimestamp){
if (utc_refvalue == UINT64_MAX)
{
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h2, m2, s2, ccx_options.millis_separator, ms2);
mstotime(end_time + ccx_decoders_xds_context.subsDelay, &h2, &m2, &s2, &ms2);
fdprintf(wb->fh, "%02u:%02u:%02u%c%03u|", h2, m2, s2, ccx_decoders_xds_context.millisSeparator, ms2);
}
else
{
fdprintf(wb->fh, "%lld%s%03d|", (get_fts() + subs_delay) / 1000, ccx_options.millis_separator, (get_fts() + subs_delay) % 1000);
fdprintf(wb->fh, "%lld%s%03d|", (end_time + ccx_decoders_xds_context.subsDelay) / 1000, ccx_decoders_xds_context.millisSeparator, (end_time + ccx_decoders_xds_context.subsDelay) % 1000);
}
}
else {
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
time_t end_time_int = (get_fts() + subs_delay) / 1000;
int end_time_dec = (get_fts() + subs_delay) % 1000;
mstotime(end_time + ccx_decoders_xds_context.subsDelay, &h2, &m2, &s2, &ms2);
time_t end_time_int = (end_time + ccx_decoders_xds_context.subsDelay) / 1000;
int end_time_dec = (end_time + ccx_decoders_xds_context.subsDelay) % 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, ccx_options.millis_separator, end_time_dec);
fdprintf(wb->fh, "%s%c%03d|", buffer, ccx_decoders_xds_context.millisSeparator, end_time_dec);
}
}
if (ccx_options.transcript_settings.showMode){
if (ccx_decoders_xds_context.transcriptFormat.showMode){
const char *mode = "XDS";
fdprintf(wb->fh, "%s|", mode);
}
if (ccx_options.transcript_settings.showCC){
if (ccx_decoders_xds_context.transcriptFormat.showCC){
fdprintf(wb->fh, "%s|", XDSclasses_short[cur_xds_packet_class]);
}
}
}
void xdsprint (const char *fmt,...)
void xdsprint (struct cc_subtitle *sub,const char *fmt,...)
{
if (wbxdsout==NULL || wbxdsout->fh==-1)
return;
xds_write_transcript_line_prefix (wbxdsout);
/* Guess we need no more than 100 bytes. */
int n, size = 100;
char *p, *np;
@@ -226,8 +266,8 @@ void xdsprint (const char *fmt,...)
if ((p = (char *) malloc (size)) == NULL)
return;
while (1)
{
while (1)
{
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
@@ -235,36 +275,33 @@ void xdsprint (const char *fmt,...)
/* If that worked, return the string. */
if (n > -1 && n < size)
{
write (wbxdsout->fh, p, n);
free (p);
xds_write_transcript_line_suffix (wbxdsout);
return;
write_xds_string(sub, p, n);
return;
}
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n+1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if ((np = (char *) realloc (p, size)) == NULL)
if ((np = (char *) realloc (p, size)) == NULL)
{
free(p);
xds_write_transcript_line_suffix (wbxdsout);
return ;
return ;
} else {
p = np;
}
}
}
}
void xds_debug_test()
void xds_debug_test(struct cc_subtitle *sub)
{
process_xds_bytes (0x05,0x02);
process_xds_bytes (0x20,0x20);
do_end_of_xds (0x2a);
do_end_of_xds (sub, 0x2a);
}
void xds_cea608_test()
void xds_cea608_test(struct cc_subtitle *sub)
{
/* This test is the sample data that comes in CEA-608. It sets the program name
to be "Star Trek". The checksum is 0x1d and the validation must succeed. */
@@ -276,7 +313,7 @@ void xds_cea608_test()
process_xds_bytes (0x02,0x03);
process_xds_bytes (0x02,0x03);
process_xds_bytes (0x6b,0x00);
do_end_of_xds (0x1d);
do_end_of_xds (sub, 0x1d);
}
int how_many_used()
@@ -299,18 +336,18 @@ void clear_xds_buffer (int num)
}
void process_xds_bytes (const unsigned char hi, int lo)
{
{
int is_new;
if (hi>=0x01 && hi<=0x0f)
{
int xds_class=(hi-1)/2; // Start codes 1 and 2 are "class type" 0, 3-4 are 2, and so on.
is_new=hi%2; // Start codes are even
dbg_print(CCX_DMT_XDS, "XDS Start: %u.%u Is new: %d | Class: %d (%s), Used buffers: %d\n",hi,lo, is_new,xds_class, XDSclasses[xds_class], how_many_used());
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Start: %u.%u Is new: %d | Class: %d (%s), Used buffers: %d\n",hi,lo, is_new,xds_class, XDSclasses[xds_class], how_many_used());
int first_free_buf=-1;
int matching_buf=-1;
for (int i=0;i<NUM_XDS_BUFFERS;i++)
{
if (xds_buffers[i].in_use &&
if (xds_buffers[i].in_use &&
xds_buffers[i].xds_class==xds_class &&
xds_buffers[i].xds_type==lo)
{
@@ -320,14 +357,14 @@ void process_xds_bytes (const unsigned char hi, int lo)
if (first_free_buf==-1 && !xds_buffers[i].in_use)
first_free_buf=i;
}
/* Here, 3 possibilities:
/* Here, 3 possibilities:
1) We already had a buffer for this class/type and matching_buf points to it
2) We didn't have a buffer for this class/type and first_free_buf points to an unused one
3) All buffers are full and we will have to skip this packet.
*/
if (matching_buf==-1 && first_free_buf==-1)
{
mprint ("Note: All XDS buffers full (bug or suicidal stream). Ignoring this one (%d,%d).\n",xds_class,lo);
ccx_common_logging.log_ftn ("Note: All XDS buffers full (bug or suicidal stream). Ignoring this one (%d,%d).\n",xds_class,lo);
cur_xds_buffer_idx=-1;
return;
@@ -341,7 +378,7 @@ void process_xds_bytes (const unsigned char hi, int lo)
xds_buffers[cur_xds_buffer_idx].xds_type=lo;
xds_buffers[cur_xds_buffer_idx].used_bytes=0;
xds_buffers[cur_xds_buffer_idx].in_use=1;
memset (xds_buffers[cur_xds_buffer_idx].bytes,0,NUM_BYTES_PER_PACKET);
memset (xds_buffers[cur_xds_buffer_idx].bytes,0,NUM_BYTES_PER_PACKET);
}
if (!is_new)
{
@@ -352,10 +389,10 @@ void process_xds_bytes (const unsigned char hi, int lo)
else
{
// Informational: 00, or 0x20-0x7F, so 01-0x1f forbidden
dbg_print(CCX_DMT_XDS, "XDS: %02X.%02X (%c, %c)\n",hi,lo,hi,lo);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS: %02X.%02X (%c, %c)\n",hi,lo,hi,lo);
if ((hi>0 && hi<=0x1f) || (lo>0 && lo<=0x1f))
{
mprint ("\rNote: Illegal XDS data");
ccx_common_logging.log_ftn ("\rNote: Illegal XDS data");
return;
}
}
@@ -364,17 +401,17 @@ void process_xds_bytes (const unsigned char hi, int lo)
// Should always happen
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes++]=hi;
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes++]=lo;
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes]=0;
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes]=0;
}
}
void xds_do_copy_generation_management_system (unsigned c1, unsigned c2)
void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned c1, unsigned c2)
{
static unsigned last_c1=-1, last_c2=-1;
static char copy_permited[256];
static char copy_permited[256];
static char aps[256];
static char rcd[256];
int changed=0;
int changed=0;
unsigned c1_6=(c1&0x40)>>6;
/* unsigned unused1=(c1&0x20)>>5; */
unsigned cgms_a_b4=(c1&0x10)>>4;
@@ -394,11 +431,11 @@ void xds_do_copy_generation_management_system (unsigned c1, unsigned c2)
if (last_c1!=c1 || last_c2!=c2)
{
changed=1;
last_c1=c1;
last_c2=c2;
last_c1=c1;
last_c2=c2;
// Changed since last time, decode
const char *copytext[4]={"Copy permited (no restrictions)", "No more copies (one generation copy has been made)",
const char *copytext[4]={"Copy permited (no restrictions)", "No more copies (one generation copy has been made)",
"One generation of copies can be made", "No copying is permited"};
const char *apstext[4]={"No APS", "PSP On; Split Burst Off", "PSP On; 2 line Split Burst On", "PSP On; 4 line Split Burst On"};
sprintf (copy_permited,"CGMS: %s", copytext[cgms_a_b4*2+cgms_a_b3]);
@@ -407,21 +444,24 @@ void xds_do_copy_generation_management_system (unsigned c1, unsigned c2)
}
xdsprint(copy_permited);
xdsprint(aps);
xdsprint(rcd);
if (changed)
if (ccx_decoders_xds_context.transcriptFormat.xds)
{
mprint ("\rXDS: %s\n",copy_permited);
mprint ("\rXDS: %s\n",aps);
mprint ("\rXDS: %s\n",rcd);
xdsprint(sub, copy_permited);
xdsprint(sub, aps);
xdsprint(sub, rcd);
}
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",copy_permited);
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",aps);
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",rcd);
if (changed)
{
ccx_common_logging.log_ftn ("\rXDS: %s\n",copy_permited);
ccx_common_logging.log_ftn ("\rXDS: %s\n",aps);
ccx_common_logging.log_ftn ("\rXDS: %s\n",rcd);
}
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",copy_permited);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",aps);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",rcd);
}
void xds_do_content_advisory (unsigned c1, unsigned c2)
void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
{
static unsigned last_c1=-1, last_c2=-1;
static char age[256];
@@ -449,14 +489,14 @@ void xds_do_content_advisory (unsigned c1, unsigned c2)
if (last_c1!=c1 || last_c2!=c2)
{
changed=1;
last_c1=c1;
last_c2=c2;
last_c1=c1;
last_c2=c2;
// Changed since last time, decode
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
if (!a1 && a0) // US TV parental guidelines
{
const char *agetext[8]={"None", "TV-Y (All Children)", "TV-Y7 (Older Children)",
"TV-G (General Audience)", "TV-PG (Parental Guidance Suggested)",
const char *agetext[8]={"None", "TV-Y (All Children)", "TV-Y7 (Older Children)",
"TV-G (General Audience)", "TV-PG (Parental Guidance Suggested)",
"TV-14 (Parents Strongly Cautioned)", "TV-MA (Mature Audience Only)", "None"};
sprintf (age,"ContentAdvisory: US TV Parental Guidelines. Age Rating: %s", agetext[g2*4+g1*2+g0]);
content[0]=0;
@@ -486,8 +526,8 @@ void xds_do_content_advisory (unsigned c1, unsigned c2)
}
if (a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
{
const char *ratingtext[8]={"Exempt", "Children", "Children eight years and older",
"General programming suitable for all audiences", "Parental Guidance",
const char *ratingtext[8]={"Exempt", "Children", "Children eight years and older",
"General programming suitable for all audiences", "Parental Guidance",
"Viewers 14 years and older", "Adult Programming", "[undefined]"};
sprintf (rating,"ContentAdvisory: Canadian English Rating: %s", ratingtext[g2*4+g1*2+g0]);
supported=1;
@@ -496,36 +536,45 @@ void xds_do_content_advisory (unsigned c1, unsigned c2)
}
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
if (!a1 && a0) // US TV parental guidelines
{
xdsprint(age);
xdsprint(content);
if (changed)
{
if (ccx_decoders_xds_context.transcriptFormat.xds)
{
mprint ("\rXDS: %s\n ",age);
mprint ("\rXDS: %s\n ",content);
xdsprint(sub, age);
xdsprint(sub, content);
}
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",age);
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",content);
if (changed)
{
ccx_common_logging.log_ftn ("\rXDS: %s\n ",age);
ccx_common_logging.log_ftn ("\rXDS: %s\n ",content);
}
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",age);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",content);
}
if (!a0 || // MPA
(a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
)
)
{
xdsprint(rating);
if (changed)
mprint ("\rXDS: %s\n ",rating);
dbg_print(CCX_DMT_XDS, "\rXDS: %s\n",rating);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, rating);
if (changed)
ccx_common_logging.log_ftn ("\rXDS: %s\n ",rating);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",rating);
}
if (changed && !supported)
mprint ("XDS: Unsupported ContentAdvisory encoding, please submit sample.\n");
if (changed && !supported)
ccx_common_logging.log_ftn ("XDS: Unsupported ContentAdvisory encoding, please submit sample.\n");
}
int xds_do_current_and_future ()
int xds_do_current_and_future (struct cc_subtitle *sub)
{
int was_proc=0;
char *str = malloc(1024);
char *tstr = NULL;
int str_len = 1024;
switch (cur_xds_packet_type)
{
case XDS_TYPE_PIN_START_TIME:
@@ -551,21 +600,21 @@ int xds_do_current_and_future ()
current_xds_month=month;
}
dbg_print(CCX_DMT_XDS, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
(cur_xds_packet_class==XDS_CLASS_CURRENT?"Current":"Future"),
date,month,hour,min);
xdsprint ( "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint (sub, "PIN (Start Time): %s %02d-%02d %02d:%02d\n",
(cur_xds_packet_class==XDS_CLASS_CURRENT?"Current":"Future"),
date,month,hour,min);
if (!xds_start_time_shown && cur_xds_packet_class==XDS_CLASS_CURRENT)
{
mprint ("\rXDS: Program changed.\n");
mprint ("XDS program start time (DD/MM HH:MM) %02d-%02d %02d:%02d\n",date,month,hour,min);
activity_xds_program_identification_number (current_xds_min,
current_xds_hour, current_xds_date, current_xds_month);
ccx_common_logging.log_ftn("\rXDS: Program changed.\n");
ccx_common_logging.log_ftn ("XDS program start time (DD/MM HH:MM) %02d-%02d %02d:%02d\n",date,month,hour,min);
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR, current_xds_min, current_xds_hour, current_xds_date, current_xds_month);
xds_start_time_shown=1;
}
}
}
break;
case XDS_TYPE_LENGH_AND_CURRENT_TIME:
@@ -575,35 +624,38 @@ int xds_do_current_and_future ()
break;
int min=cur_xds_payload[2] & 0x3f; // 6 bits
int hour = cur_xds_payload[3] & 0x1f; // 5 bits
if (!xds_program_length_shown)
mprint ("\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
if (!xds_program_length_shown)
ccx_common_logging.log_ftn ("\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
else
dbg_print(CCX_DMT_XDS, "\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
xdsprint("Program length (HH:MM): %02d:%02d ",hour,min);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, "Program length (HH:MM): %02d:%02d ",hour,min);
if (cur_xds_payload_length>6) // Next two bytes (optional) available
{
int el_min=cur_xds_payload[4] & 0x3f; // 6 bits
int el_hour = cur_xds_payload[5] & 0x1f; // 5 bits
if (!xds_program_length_shown)
mprint ("Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
ccx_common_logging.log_ftn ("Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
else
dbg_print(CCX_DMT_XDS, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
xdsprint("Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, "Elapsed (HH:MM): %02d:%02d",el_hour,el_min);
}
if (cur_xds_payload_length>8) // Next two bytes (optional) available
{
int el_sec=cur_xds_payload[6] & 0x3f; // 6 bits
int el_sec=cur_xds_payload[6] & 0x3f; // 6 bits
if (!xds_program_length_shown)
dbg_print(CCX_DMT_XDS, ":%02d",el_sec);
xdsprint("Elapsed (SS) :%02d",el_sec);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, ":%02d",el_sec);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, "Elapsed (SS) :%02d",el_sec);
}
if (!xds_program_length_shown)
printf ("\n");
ccx_common_logging.log_ftn("\n");
else
dbg_print(CCX_DMT_XDS, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\n");
xds_program_length_shown=1;
}
break;
@@ -615,21 +667,22 @@ int xds_do_current_and_future ()
for (i=2;i<cur_xds_payload_length-1;i++)
xds_program_name[i-2]=cur_xds_payload[i];
xds_program_name[i-2]=0;
dbg_print(CCX_DMT_XDS, "\rXDS Program name: %s\n",xds_program_name);
xdsprint("Program name: %s",xds_program_name);
if (cur_xds_packet_class==XDS_CLASS_CURRENT &&
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS Program name: %s\n",xds_program_name);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, "Program name: %s",xds_program_name);
if (cur_xds_packet_class==XDS_CLASS_CURRENT &&
strcmp (xds_program_name, current_xds_program_name)) // Change of program
{
if (!ccx_options.gui_mode_reports)
mprint ("\rXDS Notice: Program is now %s\n", xds_program_name);
strcpy (current_xds_program_name,xds_program_name);
activity_xds_program_name (xds_program_name);
//if (!ccx_options.gui_mode_reports)
ccx_common_logging.log_ftn ("\rXDS Notice: Program is now %s\n", xds_program_name);
strncpy (current_xds_program_name,xds_program_name, 33);
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_NAME, xds_program_name);
}
break;
}
break;
case XDS_TYPE_PROGRAM_TYPE:
was_proc=1;
was_proc=1;
if (cur_xds_payload_length<5) // We need 2 data bytes
break;
if (current_program_type_reported)
@@ -644,55 +697,58 @@ int xds_do_current_and_future ()
}
}
}
if (!(ccx_options.debug_mask & CCX_DMT_XDS) && current_program_type_reported &&
ccx_options.transcript_settings.xds == 0)
//ccx_options.export_xds==0)
if (!(ccx_common_logging.debug_mask & CCX_DMT_DECODER_XDS) && current_program_type_reported &&
ccx_decoders_xds_context.transcriptFormat.xds == 0){
break;
}
memcpy (current_xds_program_type,cur_xds_payload,cur_xds_payload_length);
current_xds_program_type[cur_xds_payload_length]=0;
if (!current_program_type_reported)
mprint ("\rXDS Program Type: ");
xds_write_transcript_line_prefix(wbxdsout);
if (wbxdsout && wbxdsout->fh!=-1)
fdprintf (wbxdsout->fh,"Program type ");
ccx_common_logging.log_ftn ("\rXDS Program Type: ");
*str = '\0';
tstr = str;
for (int i=2;i<cur_xds_payload_length - 1; i++)
{
{
if (cur_xds_payload[i]==0) // Padding
continue;
continue;
if (!current_program_type_reported)
mprint ("[%02X-", cur_xds_payload[i]);
if (wbxdsout && wbxdsout->fh!=-1)
ccx_common_logging.log_ftn ("[%02X-", cur_xds_payload[i]);
if (ccx_decoders_xds_context.transcriptFormat.xds)
{
if (cur_xds_payload[i]>=0x20 && cur_xds_payload[i]<0x7F)
fdprintf (wbxdsout->fh,"[%s] ",XDSProgramTypes[cur_xds_payload[i]-0x20]);
{
snprintf(tstr,str_len - (tstr - str),"[%s] ",XDSProgramTypes[cur_xds_payload[i]-0x20]);
tstr += strlen(tstr);
}
}
if (!current_program_type_reported)
{
if (cur_xds_payload[i]>=0x20 && cur_xds_payload[i]<0x7F)
mprint ("%s",XDSProgramTypes[cur_xds_payload[i]-0x20]);
ccx_common_logging.log_ftn ("%s",XDSProgramTypes[cur_xds_payload[i]-0x20]);
else
mprint ("ILLEGAL VALUE");
mprint ("] ");
ccx_common_logging.log_ftn ("ILLEGAL VALUE");
ccx_common_logging.log_ftn ("] ");
}
}
xds_write_transcript_line_suffix(wbxdsout);
}
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub,"Program type %s",str);
if (!current_program_type_reported)
mprint ("\n");
ccx_common_logging.log_ftn ("\n");
current_program_type_reported=1;
break;
case XDS_TYPE_CONTENT_ADVISORY:
was_proc=1;
break;
case XDS_TYPE_CONTENT_ADVISORY:
was_proc=1;
if (cur_xds_payload_length<5) // We need 2 data bytes
break;
xds_do_content_advisory (cur_xds_payload[2],cur_xds_payload[3]);
xds_do_content_advisory (sub, cur_xds_payload[2],cur_xds_payload[3]);
break;
case XDS_TYPE_AUDIO_SERVICES:
case XDS_TYPE_AUDIO_SERVICES:
was_proc=1; // I don't have any sample with this.
break;
case XDS_TYPE_CGMS:
was_proc=1;
xds_do_copy_generation_management_system (cur_xds_payload[2],cur_xds_payload[3]);
was_proc=1;
xds_do_copy_generation_management_system (sub, cur_xds_payload[2],cur_xds_payload[3]);
break;
case XDS_TYPE_PROGRAM_DESC_1:
case XDS_TYPE_PROGRAM_DESC_2:
@@ -710,31 +766,34 @@ int xds_do_current_and_future ()
for (i=2;i<cur_xds_payload_length-1;i++)
xds_desc[i-2]=cur_xds_payload[i];
xds_desc[i-2]=0;
if (xds_desc[0])
{
{
int line_num=cur_xds_packet_type-XDS_TYPE_PROGRAM_DESC_1;
if (strcmp (xds_desc, xds_program_description[line_num]))
changed=1;
if (changed)
{
mprint ("\rXDS description line %d: %s\n",line_num,xds_desc);
ccx_common_logging.log_ftn ("\rXDS description line %d: %s\n",line_num,xds_desc);
strcpy (xds_program_description[line_num], xds_desc);
}
else
{
dbg_print(CCX_DMT_XDS, "\rXDS description line %d: %s\n",line_num,xds_desc);
{
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS description line %d: %s\n",line_num,xds_desc);
}
xdsprint("XDS description line %d: %s",line_num,xds_desc);
activity_xds_program_description (line_num, xds_desc);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, "XDS description line %d: %s",line_num,xds_desc);
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_DESCRIPTION, line_num, xds_desc);
}
break;
}
}
free(str);
return was_proc;
}
int xds_do_channel ()
int xds_do_channel (struct cc_subtitle *sub)
{
int was_proc=0;
switch (cur_xds_packet_type)
@@ -746,49 +805,51 @@ int xds_do_channel ()
for (i=2;i<cur_xds_payload_length-1;i++)
xds_network_name[i-2]=cur_xds_payload[i];
xds_network_name[i-2]=0;
dbg_print(CCX_DMT_XDS, "XDS Network name: %s\n",xds_network_name);
xdsprint ("Network: %s",xds_network_name);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Network name: %s\n",xds_network_name);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint (sub, "Network: %s",xds_network_name);
if (strcmp (xds_network_name, current_xds_network_name)) // Change of station
{
mprint ("XDS Notice: Network is now %s\n", xds_network_name);
ccx_common_logging.log_ftn ("XDS Notice: Network is now %s\n", xds_network_name);
strcpy (current_xds_network_name,xds_network_name);
}
break;
case XDS_TYPE_CALL_LETTERS_AND_CHANNEL:
{
was_proc=1;
char xds_call_letters[33];
if (cur_xds_payload_length<7) // We need 4-6 data bytes
break;
char xds_call_letters[7];
if (cur_xds_payload_length != 7 && cur_xds_payload_length != 9) // We need 4-6 data bytes
break;
for (i=2;i<cur_xds_payload_length-1;i++)
{
if (cur_xds_payload)
xds_call_letters[i-2]=cur_xds_payload[i];
}
xds_call_letters[i-2]=0;
dbg_print(CCX_DMT_XDS, "XDS Network call letters: %s\n",xds_call_letters);
xdsprint ("Call Letters: %s",xds_call_letters);
if (strcmp (xds_call_letters, current_xds_call_letters)) // Change of station
xds_call_letters[i-2]=0;
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Network call letters: %s\n",xds_call_letters);
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint (sub, "Call Letters: %s",xds_call_letters);
if (strncmp (xds_call_letters, current_xds_call_letters, 7)) // Change of station
{
mprint ("XDS Notice: Network call letters now %s\n", xds_call_letters);
strcpy (current_xds_call_letters,xds_call_letters);
activity_xds_network_call_letters (current_xds_call_letters);
ccx_common_logging.log_ftn ("XDS Notice: Network call letters now %s\n", xds_call_letters);
strncpy (current_xds_call_letters, xds_call_letters, 7);
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_CALL_LETTERS, current_xds_call_letters);
}
}
break;
case XDS_TYPE_TSID:
// According to CEA-608, data here (4 bytes) are used to identify the
// According to CEA-608, data here (4 bytes) are used to identify the
// "originating analog licensee". No interesting data for us.
was_proc=1;
if (cur_xds_payload_length<7) // We need 4 data bytes
break;
break;
unsigned b1=(cur_xds_payload[2])&0x10; // Only low 4 bits from each byte
unsigned b2=(cur_xds_payload[3])&0x10;
unsigned b3=(cur_xds_payload[4])&0x10;
unsigned b4=(cur_xds_payload[5])&0x10;
unsigned tsid=(b4<<12) | (b3<<8) | (b2<<4) | b1;
if (tsid)
xdsprint ("TSID: %u",tsid);
if (tsid && ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint (sub, "TSID: %u",tsid);
break;
}
return was_proc;
@@ -796,15 +857,16 @@ int xds_do_channel ()
int xds_do_private_data ()
int xds_do_private_data (struct cc_subtitle *sub)
{
if (wbxdsout==NULL) // Only thing we can do with private data is dump it.
char *str = malloc((cur_xds_payload_length *3) + 1);
if (str==NULL) // Only thing we can do with private data is dump it.
return 1;
xds_write_transcript_line_prefix (wbxdsout);
for (int i=2;i<cur_xds_payload_length-1;i++)
fdprintf(wbxdsout->fh, "%02X ",cur_xds_payload[i]);
sprintf(str, "%02X ",cur_xds_payload[i]);
xds_write_transcript_line_suffix (wbxdsout);
xdsprint(sub,str);
free(str);
return 1;
}
@@ -812,7 +874,7 @@ int xds_do_misc ()
{
int was_proc=0;
switch (cur_xds_packet_type)
{
{
case XDS_TYPE_TIME_OF_DAY:
{
was_proc=1;
@@ -822,11 +884,11 @@ int xds_do_misc ()
int hour = cur_xds_payload[3] & 0x1f; // 5 bits
int date = cur_xds_payload[4] & 0x1f; // 5 bits
int month = cur_xds_payload[5] & 0xf; // 4 bits
int reset_seconds = (cur_xds_payload[5] & 0x20);
int reset_seconds = (cur_xds_payload[5] & 0x20);
int day_of_week = cur_xds_payload[6] & 0x7;
int year = (cur_xds_payload[7] & 0x3f) + 1990;
dbg_print(CCX_DMT_XDS, "Time of day: (YYYY/MM/DD) %04d/%02d/%02d (HH:SS) %02d:%02d DoW: %d Reset seconds: %d\n",
year,month,date,hour,min, day_of_week, reset_seconds);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Time of day: (YYYY/MM/DD) %04d/%02d/%02d (HH:SS) %02d:%02d DoW: %d Reset seconds: %d\n",
year,month,date,hour,min, day_of_week, reset_seconds);
break;
}
case XDS_TYPE_LOCAL_TIME_ZONE:
@@ -837,81 +899,90 @@ int xds_do_misc ()
// int b6 = (cur_xds_payload[2] & 0x40) >>6; // Bit 6 should always be 1
int dst = (cur_xds_payload[2] & 0x20) >>5; // Daylight Saving Time
int hour = cur_xds_payload[2] & 0x1f; // 5 bits
dbg_print(CCX_DMT_XDS, "Local Time Zone: %02d DST: %d\n",
hour, dst);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Local Time Zone: %02d DST: %d\n",
hour, dst);
break;
}
default:
was_proc=0;
break;
}
}
return was_proc;
}
void do_end_of_xds (unsigned char expected_checksum)
void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
{
if (cur_xds_buffer_idx== -1 || /* Unknown buffer, or not in use (bug) */
!xds_buffers[cur_xds_buffer_idx].in_use)
return;
cur_xds_packet_class=xds_buffers[cur_xds_buffer_idx].xds_class;
cur_xds_packet_class=xds_buffers[cur_xds_buffer_idx].xds_class;
cur_xds_payload=xds_buffers[cur_xds_buffer_idx].bytes;
cur_xds_payload_length=xds_buffers[cur_xds_buffer_idx].used_bytes;
cur_xds_packet_type=cur_xds_payload[1];
cur_xds_payload[cur_xds_payload_length++]=0x0F; // The end byte itself, added to the packet
int cs=0;
for (int i=0; i<cur_xds_payload_length;i++)
{
cs=cs+cur_xds_payload[i];
cs=cs & 0x7f; // Keep 7 bits only
int c=cur_xds_payload[i]&0x7F;
dbg_print(CCX_DMT_XDS, "%02X - %c cs: %02X\n",
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "%02X - %c cs: %02X\n",
c,(c>=0x20)?c:'?', cs);
}
cs=(128-cs) & 0x7F; // Convert to 2's complement & discard high-order bit
dbg_print(CCX_DMT_XDS, "End of XDS. Class=%d (%s), size=%d Checksum OK: %d Used buffers: %d\n",
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "End of XDS. Class=%d (%s), size=%d Checksum OK: %d Used buffers: %d\n",
cur_xds_packet_class,XDSclasses[cur_xds_packet_class],
cur_xds_payload_length,
cs==expected_checksum, how_many_used());
cs==expected_checksum, how_many_used());
if (cs!=expected_checksum || cur_xds_payload_length<3)
{
dbg_print(CCX_DMT_XDS, "Expected checksum: %02X Calculated: %02X\n", expected_checksum, cs);
clear_xds_buffer (cur_xds_buffer_idx);
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Expected checksum: %02X Calculated: %02X\n", expected_checksum, cs);
clear_xds_buffer (cur_xds_buffer_idx);
return; // Bad packets ignored as per specs
}
int was_proc=0; /* Indicated if the packet was processed. Not processed means "code to do it doesn't exist yet", not an error. */
if (cur_xds_packet_type & 0x40) // Bit 6 set
{
cur_xds_packet_class = XDS_CLASS_OUT_OF_BAND;
}
switch (cur_xds_packet_class)
{
case XDS_CLASS_FUTURE: // Info on future program
if (!(ccx_options.debug_mask & CCX_DMT_XDS)) // Don't bother processing something we don't need
if (!(ccx_common_logging.debug_mask & CCX_DMT_DECODER_XDS)) // Don't bother processing something we don't need
{
was_proc=1;
break;
break;
}
case XDS_CLASS_CURRENT: // Info on current program
was_proc = xds_do_current_and_future();
case XDS_CLASS_CURRENT: // Info on current program
was_proc = xds_do_current_and_future(sub);
break;
case XDS_CLASS_CHANNEL:
was_proc = xds_do_channel();
was_proc = xds_do_channel(sub);
break;
case XDS_CLASS_MISC:
was_proc = xds_do_misc();
break;
case XDS_CLASS_PRIVATE: // CEA-608:
// The Private Data Class is for use in any closed system for whatever that
// system wishes. It shall not be defined by this standard now or in the future.
was_proc=xds_do_private_data();
// The Private Data Class is for use in any closed system for whatever that
// system wishes. It shall not be defined by this standard now or in the future.
if (ccx_decoders_xds_context.transcriptFormat.xds)
was_proc=xds_do_private_data(sub);
break;
case XDS_CLASS_OUT_OF_BAND:
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Out-of-band data, ignored.");
was_proc = 1;
break;
}
if (!was_proc)
{
mprint ("Note: We found an currently unsupported XDS packet.\n");
ccx_common_logging.log_ftn ("Note: We found an currently unsupported XDS packet.\n");
}
clear_xds_buffer (cur_xds_buffer_idx);

View File

@@ -0,0 +1,15 @@
#ifndef _XDS_H
#define _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);
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);
#endif

View File

@@ -0,0 +1,601 @@
#include "ccx_decoders_common.h"
#include "ccx_encoders_common.h"
#include "spupng_encoder.h"
#include "608_spupng.h"
#include "utility.h"
#include "ocr.h"
#include "ccx_decoders_608.h"
#include "ccx_decoders_xds.h"
#include "ccx_common_option.h"
// These are the default settings for plain transcripts. No times, no CC or caption mode, and no XDS.
ccx_encoders_transcript_format ccx_encoders_default_transcript_settings =
{
.showStartTime = 0,
.showEndTime = 0,
.showMode = 0,
.showCC = 0,
.relativeTimestamp = 1,
.xds = 0,
.useColors = 1,
.isFinal = 0
};
static const char *sami_header= // TODO: Revise the <!-- comments
"<SAMI>\n\
<HEAD>\n\
<STYLE TYPE=\"text/css\">\n\
<!--\n\
P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n\
text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n\
.UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n\
-->\n\
</STYLE>\n\
</HEAD>\n\n\
<BODY>\n";
static const char *smptett_header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<tt xmlns:ttm=\"http://www.w3.org/ns/ttml#metadata\" xmlns:tts=\"http://www.w3.org/ns/ttml#styling\" xmlns=\"http://www.w3.org/ns/ttml\" xml:lang=\"en\">\n"
" <head>\n"
" <styling>\n"
" <style xml:id=\"speakerStyle\" tts:fontFamily=\"proportionalSansSerif\" tts:fontSize=\"150%\" tts:textAlign=\"center\" tts:displayAlign=\"center\" tts:color=\"white\" tts:textOutline=\"black 1px\"/>\n"
" </styling>\n"
" <layout>\n"
" <region xml:id=\"speaker\" tts:origin=\"10% 80%\" tts:extent=\"80% 10%\" style=\"speakerStyle\"/>\n"
" </layout>\n"
" </head>\n"
" <body>\n"
" <div>\n";
void write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
{
int used;
switch (ccx_options.write_format)
{
case CCX_OF_SAMI:
sprintf ((char *) str,"</BODY></SAMI>\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used=encode_line (ctx->buffer,(unsigned char *) str);
write(out->fh, ctx->buffer, used);
break;
case CCX_OF_SMPTETT:
sprintf ((char *) str," </div>\n </body>\n</tt>\n");
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
}
used=encode_line (ctx->buffer,(unsigned char *) str);
write (out->fh, ctx->buffer,used);
break;
case CCX_OF_SPUPNG:
write_spumux_footer(out);
break;
default: // Nothing to do, no footer on this format
break;
}
}
void write_subtitle_file_header(struct encoder_ctx *ctx,struct ccx_s_write *out)
{
int used;
switch (ccx_options.write_format)
{
case CCX_OF_SRT: // Subrip subtitles have no header
break;
case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI
//fprintf_encoded (wb->fh, sami_header);
REQUEST_BUFFER_CAPACITY(ctx,strlen (sami_header)*3);
used=encode_line (ctx->buffer,(unsigned char *) sami_header);
write (out->fh, ctx->buffer,used);
break;
case CCX_OF_SMPTETT: // This header brought to you by McPoodle's CCASDI
//fprintf_encoded (wb->fh, sami_header);
REQUEST_BUFFER_CAPACITY(ctx,strlen (smptett_header)*3);
used=encode_line (ctx->buffer,(unsigned char *) smptett_header);
write(out->fh, ctx->buffer, used);
break;
case CCX_OF_RCWT: // Write header
if (ccx_options.teletext_mode == CCX_TXT_IN_USE)
rcwt_header[7] = 2; // sets file format version
if (ccx_options.send_to_srv)
net_send_header(rcwt_header, sizeof(rcwt_header));
else
write(out->fh, rcwt_header, sizeof(rcwt_header));
break;
case CCX_OF_SPUPNG:
write_spumux_header(out);
break;
case CCX_OF_TRANSCRIPT: // No header. Fall thru
default:
break;
}
}
void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx *context, int line_number)
{
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
LLONG start_time = data->start_time;
LLONG end_time = data->end_time;
if (ccx_options.sentence_cap)
{
capitalize (line_number,data);
correct_case(line_number,data);
}
int length = get_decoder_line_basic (subline, line_number, data,ccx_options.trim_subs,ccx_options.encoding);
if (ccx_options.encoding!=CCX_ENC_UNICODE)
{
dbg_print(CCX_DMT_DECODER_608, "\r");
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
}
if (length>0)
{
if (data->start_time == -1)
{
// CFS: Means that the line has characters but we don't have a timestamp for the first one. Since the timestamp
// is set for example by the write_char function, it possible that we don't have one in empty lines (unclear)
// For now, let's not consider this a bug as before and just return.
// fatal (EXIT_BUG_BUG, "Bug in timedtranscript (ts_start_of_current_line==-1). Please report.");
return;
}
if (ccx_options.transcript_settings.showStartTime){
char buf1[80];
if (ccx_options.transcript_settings.relativeTimestamp){
millis_to_date(start_time + context->subs_delay, buf1);
fdprintf(context->out->fh, "%s|", buf1);
}
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(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
}
}
if (ccx_options.transcript_settings.showEndTime){
char buf2[80];
if (ccx_options.transcript_settings.relativeTimestamp){
millis_to_date(end_time, buf2);
fdprintf(context->out->fh, "%s|", buf2);
}
else {
mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
time_t end_time_int = (end_time + context->subs_delay) / 1000;
int end_time_dec = (end_time + context->subs_delay) % 1000;
struct tm *end_time_struct = gmtime(&end_time_int);
strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
}
}
if (ccx_options.transcript_settings.showCC){
fdprintf(context->out->fh, "CC%d|", data->my_field == 1 ? data->channel : data->channel + 2); // Data from field 2 is CC3 or 4
}
if (ccx_options.transcript_settings.showMode){
const char *mode = "???";
switch (data->mode)
{
case MODE_POPON:
mode = "POP";
break;
case MODE_FAKE_ROLLUP_1:
mode = "RU1";
break;
case MODE_ROLLUP_2:
mode = "RU2";
break;
case MODE_ROLLUP_3:
mode = "RU3";
break;
case MODE_ROLLUP_4:
mode = "RU4";
break;
case MODE_TEXT:
mode = "TXT";
break;
case MODE_PAINTON:
mode = "PAI";
break;
}
fdprintf(context->out->fh, "%s|", mode);
}
write(context->out->fh, subline, length);
write(context->out->fh, encoded_crlf, encoded_crlf_length);
}
// fprintf (wb->fh,encoded_crlf);
}
int write_cc_buffer_as_transcript2(struct eia608_screen *data, struct encoder_ctx *context)
{
int wrote_something = 0;
dbg_print(CCX_DMT_DECODER_608, "\n- - - TRANSCRIPT caption - - -\n");
for (int i=0;i<15;i++)
{
if (data->row_used[i])
{
write_cc_line_as_transcript2 (data, context, i);
}
wrote_something=1;
}
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
return wrote_something;
}
int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
{
int ret = 0;
struct cc_bitmap* rect;
#ifdef ENABLE_OCR
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
#endif
LLONG start_time, end_time;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
start_time = context->prev_start + context->subs_delay;
end_time = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
start_time = sub->start_time + context->subs_delay;
end_time = sub->end_time - 1;
}
if(sub->nb_data == 0 )
return ret;
rect = sub->data;
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
#if ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *token = NULL;
token = strtok(rect[0].ocr_text ,"\r\n");
while (token)
{
if (ccx_options.transcript_settings.showStartTime)
{
char buf1[80];
if (ccx_options.transcript_settings.relativeTimestamp)
{
millis_to_date(start_time + context->subs_delay, buf1);
fdprintf(context->out->fh, "%s|", buf1);
}
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(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
}
}
if (ccx_options.transcript_settings.showEndTime)
{
char buf2[80];
if (ccx_options.transcript_settings.relativeTimestamp)
{
millis_to_date(end_time, buf2);
fdprintf(context->out->fh, "%s|", buf2);
}
else
{
mstotime(get_fts() + context->subs_delay, &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(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
}
}
if (ccx_options.transcript_settings.showCC)
{
fdprintf(context->out->fh,"%s|",language[sub->lang_index]);
}
if (ccx_options.transcript_settings.showMode)
{
fdprintf(context->out->fh,"DVB|");
}
fdprintf(context->out->fh,"%s\n",token);
token = strtok(NULL,"\r\n");
}
}
}
#endif
sub->nb_data = 0;
freep(&sub->data);
return ret;
}
void try_to_add_end_credits(struct encoder_ctx *context, struct ccx_s_write *out)
{
LLONG window, length, st, end;
if (out->fh == -1)
return;
window=get_fts()-context->last_displayed_subs_ms-1;
if (window<ccx_options.endcreditsforatleast.time_in_ms) // Won't happen, window is too short
return;
length=ccx_options.endcreditsforatmost.time_in_ms > window ?
window : ccx_options.endcreditsforatmost.time_in_ms;
st=get_fts()-length-1;
end=get_fts();
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
write_stringz_as_srt(ccx_options.end_credits_text, context, st, end);
break;
case CCX_OF_SAMI:
write_stringz_as_sami(ccx_options.end_credits_text, context, st, end);
break;
case CCX_OF_SMPTETT:
write_stringz_as_smptett(ccx_options.end_credits_text, context, st, end);
break ;
default:
// Do nothing for the rest
break;
}
}
void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
{
LLONG st, end, window, length;
LLONG l = start_ms + context->subs_delay;
// We have a windows from last_displayed_subs_ms to l - we need to see if it fits
if (l<ccx_options.startcreditsnotbefore.time_in_ms) // Too early
return;
if (context->last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
return;
st = ccx_options.startcreditsnotbefore.time_in_ms>(context->last_displayed_subs_ms+1) ?
ccx_options.startcreditsnotbefore.time_in_ms : (context->last_displayed_subs_ms+1); // When would credits actually start
end = ccx_options.startcreditsnotafter.time_in_ms<(l-1) ?
ccx_options.startcreditsnotafter.time_in_ms : (l-1);
window = end-st; // Allowable time in MS
if (ccx_options.startcreditsforatleast.time_in_ms>window) // Window is too short
return;
length=ccx_options.startcreditsforatmost.time_in_ms > window ?
window : ccx_options.startcreditsforatmost.time_in_ms;
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
context->last_displayed_subs_ms, l);
dbg_print(CCX_DMT_VERBOSE, "Not before: %lld Not after: %lld\n",
ccx_options.startcreditsnotbefore.time_in_ms,
ccx_options.startcreditsnotafter.time_in_ms);
dbg_print(CCX_DMT_VERBOSE, "Start of window: %lld End of window: %lld\n",st,end);
if (window>length+2)
{
// Center in time window
LLONG pad=window-length;
st+=(pad/2);
}
end=st+length;
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
write_stringz_as_srt(ccx_options.start_credits_text,context,st,end);
break;
case CCX_OF_SAMI:
write_stringz_as_sami(ccx_options.start_credits_text, context, st, end);
break;
case CCX_OF_SMPTETT:
write_stringz_as_smptett(ccx_options.start_credits_text, context, st, end);
break;
default:
// Do nothing for the rest
break;
}
context->startcredits_displayed=1;
return;
}
int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out)
{
ctx->buffer = (unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY);
if (ctx->buffer==NULL)
return -1;
ctx->capacity=INITIAL_ENC_BUFFER_CAPACITY;
ctx->srt_counter = 0;
ctx->out = out;
/** used in case of SUB_EOD_MARKER */
ctx->prev_start = -1;
write_subtitle_file_header(ctx,out);
return 0;
}
void set_encoder_last_displayed_subs_ms(struct encoder_ctx *ctx, LLONG last_displayed_subs_ms)
{
ctx->last_displayed_subs_ms = last_displayed_subs_ms;
}
void set_encoder_subs_delay(struct encoder_ctx *ctx, LLONG subs_delay)
{
ctx->subs_delay = subs_delay;
}
void set_encoder_startcredits_displayed(struct encoder_ctx *ctx, int startcredits_displayed)
{
ctx->startcredits_displayed = startcredits_displayed;
}
void dinit_encoder(struct encoder_ctx *ctx)
{
if (ccx_options.end_credits_text!=NULL)
try_to_add_end_credits(ctx,ctx->out);
write_subtitle_file_footer(ctx,ctx->out);
freep(&ctx->buffer);
ctx->capacity = 0;
}
int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
{
int wrote_something = 0;
if (sub->type == CC_608)
{
struct eia608_screen *data = NULL;
for(data = sub->data; sub->nb_data ; sub->nb_data--,data++)
{
// Determine context based on channel. This replaces the code that was above, as this was incomplete (for cases where -12 was used for example)
//if (ccx_options.extract!=1)
//context++;
if (data->my_field == 2)
context++;
new_sentence=1;
if(data->format == SFORMAT_XDS)
{
xds_write_transcript_line_prefix (context->out, data->start_time, data->end_time,data->cur_xds_packet_class);
if(data->xds_len > 0)
write (context->out->fh, data->xds_str,data->xds_len);
freep (&data->xds_str);
xds_write_transcript_line_suffix (context->out);
continue;
}
if(!data->start_time)
break;
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
try_to_add_start_credits(context, data->start_time);
wrote_something = write_cc_buffer_as_srt(data, context);
break;
case CCX_OF_SAMI:
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
try_to_add_start_credits(context, data->start_time);
wrote_something = write_cc_buffer_as_sami(data, context);
break;
case CCX_OF_SMPTETT:
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
try_to_add_start_credits(context, data->start_time);
wrote_something = write_cc_buffer_as_smptett(data, context);
break;
case CCX_OF_TRANSCRIPT:
wrote_something = write_cc_buffer_as_transcript2(data, context);
break;
case CCX_OF_SPUPNG:
wrote_something = write_cc_buffer_as_spupng(data, context);
break;
default:
break;
}
if (wrote_something)
context->last_displayed_subs_ms=get_fts() + context->subs_delay;
if (ccx_options.gui_mode_reports)
write_cc_buffer_to_gui(sub->data, context);
}
freep(&sub->data);
}
if(sub->type == CC_BITMAP)
{
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
try_to_add_start_credits(context, sub->start_time);
wrote_something = write_cc_bitmap_as_srt(sub, context);
case CCX_OF_SAMI:
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
try_to_add_start_credits(context, sub->start_time);
wrote_something = write_cc_bitmap_as_sami(sub, context);
case CCX_OF_SMPTETT:
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
try_to_add_start_credits(context, sub->start_time);
wrote_something = write_cc_bitmap_as_smptett(sub, context);
case CCX_OF_TRANSCRIPT:
wrote_something = write_cc_bitmap_as_transcript(sub, context);
break;
case CCX_OF_SPUPNG:
wrote_something = write_cc_bitmap_as_spupng(sub, context);
break;
default:
break;
}
}
if (!sub->nb_data)
freep(&sub->data);
return wrote_something;
}
void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *context)
{
unsigned h1, m1, s1, ms1;
unsigned h2, m2, s2, ms2;
LLONG ms_start;
int with_data = 0;
for (int i = 0; i<15; i++)
{
if (data->row_used[i])
with_data = 1;
}
if (!with_data)
return;
ms_start = data->start_time;
ms_start += context->subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return;
int time_reported = 0;
for (int i = 0; i<15; i++)
{
if (data->row_used[i])
{
fprintf(stderr, "###SUBTITLE#");
if (!time_reported)
{
LLONG ms_end = 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.
// Note, only MM:SS here as we need to save space in the preview window
fprintf(stderr, "%02u:%02u#%02u:%02u#",
h1 * 60 + m1, s1, h2 * 60 + m2, s2);
time_reported = 1;
}
else
fprintf(stderr, "##");
// We don't capitalize here because whatever function that was used
// before to write to file already took care of it.
int length = get_decoder_line_encoded_for_gui(subline, i, data);
fwrite(subline, 1, length, stderr);
fwrite("\n", 1, 1, stderr);
}
}
fflush(stderr);
}

View File

@@ -0,0 +1,88 @@
#ifndef _CC_ENCODER_COMMON_H
#define _CC_ENCODER_COMMON_H
#include "ccx_common_structs.h"
#include "ccx_decoders_structs.h"
#include "ccx_encoders_structs.h"
#include "ccx_encoders_helpers.h"
#define REQUEST_BUFFER_CAPACITY(ctx,length) if (length>ctx->capacity) \
{ctx->capacity = length * 2; ctx->buffer = (unsigned char*)realloc(ctx->buffer, ctx->capacity); \
if (ctx->buffer == NULL) { fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
}
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
/**
* Context of encoder, This structure gives single interface
* to all encoder
*/
struct encoder_ctx
{
/* common buffer used by all encoder */
unsigned char *buffer;
/* capacity of buffer */
unsigned int capacity;
/* keep count of srt subtitle*/
unsigned int srt_counter;
/* 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;
};
#define INITIAL_ENC_BUFFER_CAPACITY 2048
/**
* Inialize encoder context with output context
* allocate initial memory to buffer of context
* write subtitle header to file refrenced by
* output context
*
* @param ctx preallocated encoder ctx
* @param out output context
*
* @return 0 on SUCESS, -1 on failure
*/
int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out);
/**
* try to add end credits in subtitle file and then write subtitle
* footer
*
* deallocate encoder ctx, so before using encoder_ctx again
* after deallocating user need to allocate encoder ctx again
*
* @oaram ctx Initialized encoder ctx using init_encoder
*/
void dinit_encoder(struct encoder_ctx *ctx);
/**
* @param ctx encoder context
* @param sub subtitle context returned by decoder
*/
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context);
void write_stringz_as_srt(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_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);
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_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context);
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context);
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context);
void set_encoder_last_displayed_subs_ms(struct encoder_ctx *ctx, LLONG last_displayed_subs_ms);
void set_encoder_subs_delay(struct encoder_ctx *ctx, LLONG subs_delay);
void set_encoder_startcredits_displayed(struct encoder_ctx *ctx, int startcredits_displayed);
#endif

View File

@@ -0,0 +1,392 @@
#include "ccx_encoders_helpers.h"
#include "ccx_common_char_encoding.h"
#include "ccx_common_constants.h"
#include "ccx_common_structs.h"
#include "ccx_decoders_common.h"
#ifdef _MSC_VER
#define strcasecmp stricmp
#endif
// userdefined rgb color
unsigned char usercolor_rgb[8] = "";
static int spell_builtin_added = 0; // so we don't do it twice
// Case arrays
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[] =
{
"I", "I'd", "I've", "I'd", "I'll",
"January", "February", "March", "April", // May skipped intentionally
"June", "July", "August", "September", "October", "November",
"December", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday", "Halloween", "United States",
"Spain", "France", "Italy", "England",
NULL
};
int string_cmp2(const void *p1, const void *p2, void *arg)
{
return strcasecmp(*(char**)p1, *(char**)p2);
}
int string_cmp(const void *p1, const void *p2)
{
return string_cmp2(p1, p2, NULL);
}
void correct_case(int line_num, struct eia608_screen *data)
{
char delim[64] = {
' ', '\n', '\r', 0x89, 0x99,
'!', '"', '#', '%', '&',
'\'', '(', ')', ';', '<',
'=', '>', '?', '[', '\\',
']', '*', '+', ',', '-',
'.', '/', ':', '^', '_',
'{', '|', '}', '~', '\0' };
char *line = strdup(((char*)data->characters[line_num]));
char *oline = (char*)data->characters[line_num];
char *c = strtok(line, delim);
do
{
char **index = bsearch(&c, spell_lower, spell_words, sizeof(*spell_lower), string_cmp);
if (index)
{
char *correct_c = *(spell_correct + (index - spell_lower));
size_t len = strlen(correct_c);
memcpy(oline + (c - line), correct_c, len);
}
} while ((c = strtok(NULL, delim)) != NULL);
free(line);
}
void capitalize(int line_num, struct eia608_screen *data)
{
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
{
switch (data->characters[line_num][i])
{
case ' ':
case 0x89: // This is a transparent space
case '-':
break;
case '.': // Fallthrough
case '?': // Fallthrough
case '!':
case ':':
new_sentence = 1;
break;
default:
if (new_sentence)
data->characters[line_num][i] = cctoupper(data->characters[line_num][i]);
else
data->characters[line_num][i] = cctolower(data->characters[line_num][i]);
new_sentence = 0;
break;
}
}
}
// Encodes a generic string. Note that since we use the encoders for closed caption
// data, text would have to be encoded as CCs... so using special characters here
// it's a bad idea.
unsigned encode_line(unsigned char *buffer, unsigned char *text)
{
unsigned bytes = 0;
while (*text)
{
switch (ccx_encoders_helpers_settings.encoding)
{
case CCX_ENC_UTF_8:
case CCX_ENC_LATIN_1:
*buffer = *text;
bytes++;
buffer++;
break;
case CCX_ENC_UNICODE:
*buffer = *text;
*(buffer + 1) = 0;
bytes += 2;
buffer += 2;
break;
}
text++;
}
return bytes;
}
unsigned get_decoder_line_encoded_for_gui(unsigned char *buffer, int line_num, struct eia608_screen *data)
{
unsigned char *line = data->characters[line_num];
unsigned char *orig = buffer; // Keep for debugging
int first = 0, last = 31;
find_limit_characters(line, &first, &last);
for (int i = first; i <= last; i++)
{
get_char_in_latin_1(buffer, line[i]);
buffer++;
}
*buffer = 0;
return (unsigned)(buffer - orig); // Return length
}
unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font)
{
for (int l = strlen(tagstack) - 1; l >= 0; l--)
{
char cur = tagstack[l];
switch (cur)
{
case 'F':
buffer += encode_line(buffer, (unsigned char *) "</font>");
(*pchanged_font)--;
break;
case 'U':
buffer += encode_line(buffer, (unsigned char *) "</u>");
(*punderlined)--;
break;
case 'I':
buffer += encode_line(buffer, (unsigned char *) "</i>");
(*pitalics)--;
break;
}
tagstack[l] = 0; // Remove from stack
if (cur == tagtype) // We closed up to the required tag, done
return buffer;
}
if (tagtype != 'A') // All
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Mismatched tags in encoding, this is a bug, please report");
return buffer;
}
unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct eia608_screen *data)
{
int col = COL_WHITE;
int underlined = 0;
int italics = 0;
int changed_font = 0;
char tagstack[128] = ""; // Keep track of opening/closing tags
unsigned char *line = data->characters[line_num];
unsigned char *orig = buffer; // Keep for debugging
int first = 0, last = 31;
if (ccx_encoders_helpers_settings.trim_subs)
find_limit_characters(line, &first, &last);
for (int i = first; i <= last; i++)
{
// Handle color
int its_col = data->colors[line_num][i];
if (its_col != col && !ccx_encoders_helpers_settings.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);
// Add new font tag
buffer += encode_line(buffer, (unsigned char*)color_text[its_col][1]);
if (its_col == COL_USERDEFINED)
{
// The previous sentence doesn't copy the whole
// <font> tag, just up to the quote before the color
buffer += encode_line(buffer, (unsigned char*)usercolor_rgb);
buffer += encode_line(buffer, (unsigned char*) "\">");
}
if (color_text[its_col][1][0]) // That means a <font> was added to the buffer
{
strcat(tagstack, "F");
changed_font++;
}
col = its_col;
}
// Handle underlined
int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
if (is_underlined && underlined == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open underline
{
buffer += encode_line(buffer, (unsigned char *) "<u>");
strcat(tagstack, "U");
underlined++;
}
if (is_underlined == 0 && underlined && !ccx_encoders_helpers_settings.no_type_setting) // Close underline
{
buffer = close_tag(buffer, tagstack, 'U', &underlined, &italics, &changed_font);
}
// Handle italics
int has_ita = data->fonts[line_num][i] & FONT_ITALICS;
if (has_ita && italics == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open italics
{
buffer += encode_line(buffer, (unsigned char *) "<i>");
strcat(tagstack, "I");
italics++;
}
if (has_ita == 0 && italics && !ccx_encoders_helpers_settings.no_type_setting) // Close italics
{
buffer = close_tag(buffer, tagstack, 'I', &underlined, &italics, &changed_font);
}
int bytes = 0;
switch (ccx_encoders_helpers_settings.encoding)
{
case CCX_ENC_UTF_8:
bytes = get_char_in_utf_8(buffer, line[i]);
break;
case CCX_ENC_LATIN_1:
get_char_in_latin_1(buffer, line[i]);
bytes = 1;
break;
case CCX_ENC_UNICODE:
get_char_in_unicode(buffer, line[i]);
bytes = 2;
break;
}
buffer += bytes;
}
buffer = close_tag(buffer, tagstack, 'A', &underlined, &italics, &changed_font);
if (underlined || italics || changed_font)
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;
return (unsigned)(buffer - orig); // Return length
}
/*void delete_all_lines_but_current(ccx_decoder_608_context *context, struct eia608_screen *data, int row)
{
for (int i=0;i<15;i++)
{
if (i!=row)
{
memset(data->characters[i], ' ', CCX_DECODER_608_SCREEN_WIDTH);
data->characters[i][CCX_DECODER_608_SCREEN_WIDTH] = 0;
memset(data->colors[i], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH + 1);
memset(data->fonts[i], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH + 1);
data->row_used[i]=0;
}
}
}*/
/*void fprintf_encoded (struct encoder_ctx *ctx,FILE *fh, const char *string)
{
int used;
REQUEST_BUFFER_CAPACITY(ctx,strlen (string)*3);
used=encode_line (ctx->buffer,(unsigned char *) string);
fwrite (ctx->buffer,used,1,fh);
}*/
int add_word(const char *word)
{
char *new_lower;
char *new_correct;
char **ptr_lower;
char **ptr_correct;
int i;
if (spell_words == spell_capacity)
{
// Time to grow
spell_capacity += 50;
ptr_lower = (char **)realloc(spell_lower, sizeof (char *)*
spell_capacity);
ptr_correct = (char **)realloc(spell_correct, sizeof (char *)*
spell_capacity);
}
size_t len = strlen(word);
new_lower = (char *)malloc(len + 1);
new_correct = (char *)malloc(len + 1);
if (ptr_lower == NULL || ptr_correct == NULL ||
new_lower == NULL || new_correct == NULL)
{
spell_capacity = 0;
for (i = 0; i < spell_words; i++)
{
freep(&spell_lower[spell_words]);
freep(&spell_correct[spell_words]);
}
freep(&spell_lower);
freep(&spell_correct);
freep(&ptr_lower);
freep(&ptr_correct);
freep(&new_lower);
freep(&new_correct);
spell_words = 0;
return -1;
}
else
{
spell_lower = ptr_lower;
spell_correct = ptr_correct;
}
strcpy(new_correct, word);
for (size_t i = 0; i<len; i++)
{
char c = new_correct[i];
c = tolower(c); // TO-DO: Add Spanish characters
new_lower[i] = c;
}
new_lower[len] = 0;
spell_lower[spell_words] = new_lower;
spell_correct[spell_words] = new_correct;
spell_words++;
return 0;
}
int add_built_in_words(void)
{
if (!spell_builtin_added)
{
int i = 0;
while (spell_builtin[i] != NULL)
{
if (add_word(spell_builtin[i]))
return -1;
i++;
}
spell_builtin_added = 1;
}
return 0;
}
/**
* @param base points to the start of the array
* @param nb number of element in array
* @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.
* @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)
{
unsigned char *lbase = (unsigned char*)base;
unsigned char *tmp = (unsigned char*)malloc(size);
for (int gap = nb / 2; gap > 0; gap = gap / 2)
{
int p, j;
for (p = gap; p < nb; p++)
{
memcpy(tmp, lbase + (p *size), size);
for (j = p; j >= gap && (compar(tmp, lbase + ((j - gap) * size), arg) < 0); j -= gap)
{
memcpy(lbase + (j*size), lbase + ((j - gap) * size), size);
}
memcpy(lbase + (j *size), tmp, size);
}
}
free(tmp);
}
void ccx_encoders_helpers_perform_shellsort_words(void)
{
shell_sort(spell_lower, spell_words, sizeof(*spell_lower), string_cmp2, NULL);
shell_sort(spell_correct, spell_words, sizeof(*spell_correct), string_cmp2, NULL);
}
void ccx_encoders_helpers_setup(enum ccx_encoding_type encoding,int no_font_color,int no_type_setting,int trim_subs){
ccx_encoders_helpers_settings.encoding = encoding;
ccx_encoders_helpers_settings.no_font_color = no_font_color;
ccx_encoders_helpers_settings.no_type_setting = no_type_setting;
ccx_encoders_helpers_settings.trim_subs = trim_subs;
}

View File

@@ -0,0 +1,39 @@
#ifndef _CCX_ENCODERS_HELPERS_H
#define _CCX_ENCODERS_HELPERS_H
#include "ccx_common_common.h"
#include "ccx_common_constants.h"
#include "ccx_decoders_structs.h"
#include "ccx_decoders_608.h"
extern char **spell_lower;
extern char **spell_correct;
extern int spell_words;
extern int spell_capacity;
extern unsigned char usercolor_rgb[8];
struct ccx_encoders_helpers_settings_t {
int trim_subs;
int no_font_color;
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);
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);
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);
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg);
void ccx_encoders_helpers_perform_shellsort_words(void);
void ccx_encoders_helpers_setup(enum ccx_encoding_type encoding, int no_font_color, int no_type_setting, int trim_subs);
#endif

View File

@@ -0,0 +1,25 @@
#ifndef CCX_ENCODERS_STRUCTS_H
typedef struct ccx_encoders_transcript_format {
// TODO: add more options, and (perhaps) reduce other ccextractor options?
int showStartTime, showEndTime; // Show start and/or end time.
int showMode; // Show which mode if available (E.G.: POP, RU1, ...)
int showCC; // Show which CC channel has been captured.
int relativeTimestamp; // Timestamps relative to start of sample or in UTC?
int xds; // Show XDS or not
int useColors; // Add colors or no colors
int isFinal; // Used to determine if these parameters should be changed afterwards.
} ccx_encoders_transcript_format;
struct ccx_s_write
{
int multiple_files;
char *first_input_file;
int fh;
char *filename;
void* spupng_data;
};
#define CCX_ENCODERS_STRUCTS_H
#endif

View File

@@ -1,4 +1,5 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "configuration.h"
#include <stddef.h>
#define CNF_FILE "ccextractor.cnf"
@@ -44,7 +45,6 @@ static int set_int(void *var, char*val)
struct conf_map configuration_map[] = {
{"INPUT_SOURCE",offsetof(struct ccx_s_options,input_source),set_int},
{"BUFFER_INPUT",offsetof(struct ccx_s_options,buffer_input),set_int},
{"DIRECT_ROLLUP",offsetof(struct ccx_s_options,direct_rollup),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},
@@ -61,8 +61,6 @@ struct conf_map configuration_map[] = {
{"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},
{"NO_ROLL_UP",offsetof(struct ccx_s_options,norollup),set_int},
{"FORCED_RU",offsetof(struct ccx_s_options,forced_ru),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},
@@ -71,7 +69,6 @@ struct conf_map configuration_map[] = {
{"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},
{"SCREEN_TO_PROCESS",offsetof(struct ccx_s_options,screens_to_process),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},
@@ -89,6 +86,12 @@ struct conf_map configuration_map[] = {
{"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 },
{ "FORCED_RU", offsetof(struct ccx_s_options, settings_608.force_rollup), set_int },
{ "DIRECT_ROLLUP", offsetof(struct ccx_s_options, settings_608.direct_rollup), set_int },
{ "SCREEN_TO_PROCESS", offsetof(struct ccx_s_options, settings_608.screens_to_process), set_int },
{NULL}
};
static int parse_opts(char *str, struct ccx_s_options *opt)
@@ -115,14 +118,17 @@ static void parse_file(FILE *f,struct ccx_s_options *opt)
int comments = 0;
int i = 0;
int ret = 0;
while ((c = fgetc(f)) != EOF )
*str = '\0';
while ((c = (char)fgetc(f)) != EOF )
{
if( c == '\n')
{
if( str[0] != '\0')
{
ret = parse_opts(str,opt);
if(ret < 0)
mprint("invalid configuration file\n");
}
comments = 0;
i = 0;
str[0] = '\0';
@@ -140,10 +146,10 @@ static void parse_file(FILE *f,struct ccx_s_options *opt)
}
void parse_configuration(struct ccx_s_options *opt)
{
FILE *f = NULL;
if( (f = fopen(CNF_FILE,"r") ) != NULL)
{
FILE *f = NULL;
if( (f = fopen(CNF_FILE,"r") ) != NULL)
{
parse_file(f,opt);
}
fclose(f);
}
}

View File

@@ -21,20 +21,11 @@
#include <limits.h>
#include <errno.h>
#ifdef _MSC_VER
#define snprintf(str,size,format,...) _snprintf(str,size-1,format,__VA_ARGS__)
#endif
#include "dvb_subtitle_decoder.h"
#include "spupng_encoder.h"
#include "ocr.h"
#include "utility.h"
#define DEBUG
#ifdef DEBUG
#define PNG_DEBUG 3
#include "png.h"
#endif
#include "ccx_decoders_common.h"
#include "ocr.h"
#define DVBSUB_PAGE_SEGMENT 0x10
#define DVBSUB_REGION_SEGMENT 0x11
@@ -95,7 +86,6 @@ const uint8_t crop_tab[256 + 2 * MAX_NEG_CROP] = { times256(0x00), 0x00, 0x01,
#define cm (crop_tab + MAX_NEG_CROP)
const char *dvb_language[] = { "und", "eng", "fin", NULL };
static __inline unsigned int bytestream_get_byte(const uint8_t **b)
{
@@ -161,7 +151,7 @@ static __inline unsigned int get_bits(GetBitContext *s, int n)
unsigned int re_cache = 0;
unsigned int re_size_plus8 = s->size_in_bits_plus8;
if (n <= 0 && n > 25)
if (n <= 0 || n > 25)
return -1;
re_cache = RB32( s->buffer + (re_index >> 3 )) << (re_index & 7);
@@ -189,308 +179,6 @@ static __inline unsigned int get_bits1(GetBitContext *s)
return result;
}
static void freep(void *arg)
{
void **ptr = (void **) arg;
if (*ptr)
free(*ptr);
*ptr = NULL;
}
#ifdef DEBUG
struct transIntensity
{
uint8_t *t;
uint8_t *i;
};
int check_trans_tn_intensity(const void *p1, const void *p2, void *arg)
{
struct transIntensity *ti = arg;
unsigned char* tmp = (unsigned char*)p1;
unsigned char* act = (unsigned char*)p2;
if (ti->t[*tmp] < ti->t[*act] || (ti->t[*tmp] == ti->t[*act] && ti->i[*tmp] < ti->i[*act]))
return -1;
else if (ti->t[*tmp] == ti->t[*act] && ti->i[*tmp] == ti->i[*act])
return 0;
return 1;
}
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
uint8_t depth)
{
for (int i = 0; i < depth; i++)
{
palette[i].red = ((clut[i] >> 16) & 0xff);
palette[i].green = ((clut[i] >> 8) & 0xff);
palette[i].blue = (clut[i] & 0xff);
alpha[i] = ((clut[i] >> 24) & 0xff);
}
return 0;
}
/*
* @param alpha out
* @param intensity in
* @param palette out should be already initialized
* @param bitmap in
* @param size in size of bitmap
* @param max_color in
* @param nb_color in
*/
int quantize_map(png_byte *alpha, uint8_t *intensity, png_color *palette,
uint8_t *bitmap, int size, int max_color, int nb_color)
{
/*
* occurrence of color in image
*/
uint32_t *histogram = NULL;
/* intensity ordered table */
uint8_t *iot = NULL;
/* array of color with most occurrence according to histogram
* save index of intensity order table
*/
uint32_t *mcit = NULL;
struct transIntensity ti = { alpha,intensity};
int ret = 0;
histogram = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
if (!histogram)
{
ret = -1;
goto end;
}
iot = (uint8_t*) malloc(nb_color * sizeof(uint8_t));
if (!iot)
{
ret = -1;
goto end;
}
mcit = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
if (!mcit)
{
ret = -1;
goto end;
}
memset(histogram, 0, nb_color * sizeof(uint32_t));
for (int i = 0; i < nb_color; i++)
{
iot[i] = i;
}
memset(mcit, 0, nb_color * sizeof(uint32_t));
/* calculate histogram of image */
for (int i = 0; i < size; i++)
{
histogram[bitmap[i]]++;
}
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
/* using selection sort since need to find only max_color */
for (int i = 0; i < max_color; i++)
{
uint32_t max_val = 0;
uint32_t max_ind = 0;
int j;
for (j = 0; j < nb_color; j++)
{
if (max_val < histogram[iot[j]])
{
max_val = histogram[iot[j]];
max_ind = j;
}
}
for (j = i; j > 0 && max_ind < mcit[j - 1]; j--)
{
mcit[j] = mcit[j - 1];
}
mcit[j] = max_ind;
histogram[iot[max_ind]] = 0;
}
for (int i = 0, mxi = 0; i < nb_color; i++)
{
int step, inc;
if (i == mcit[mxi])
{
mxi = (mxi < max_color) ? mxi + 1 : mxi;
continue;
}
inc = (mxi) ? -1 : 0;
step = mcit[mxi + inc] + ((mcit[mxi] - mcit[mxi + inc]) / 3);
if (i <= step)
{
int index = iot[mcit[mxi + inc]];
alpha[i] = alpha[index];
palette[i].red = palette[index].red;
palette[i].blue = palette[index].blue;
palette[i].green = palette[index].green;
}
else
{
int index = iot[mcit[mxi]];
alpha[i] = alpha[index];
palette[i].red = palette[index].red;
palette[i].blue = palette[index].blue;
palette[i].green = palette[index].green;
}
}
end: freep(&histogram);
freep(&mcit);
freep(&iot);
return ret;
}
static int pre_process_bitmap(png_color **palette, png_byte **alpha, int size,
uint32_t *clut, uint8_t *luit, uint8_t *bitmap, uint8_t depth)
{
/*local pointer to palette */
png_color *lpalette = NULL;
/* local pointer to alpha */
png_byte *lalpha = NULL;
int nb_color = (1<< depth);
int ret = 0;
lpalette = (png_color*) malloc(nb_color * sizeof(png_color));
if(!lpalette)
{
ret = -1;
goto end;
}
lalpha = (png_byte*) malloc(nb_color * sizeof(png_byte));
if(!lalpha)
{
ret = -1;
goto end;
}
if(clut)
mapclut_paletee(lpalette, lalpha, clut, nb_color);
else
{
/* initialize colors with white */
memset(palette,0xff,sizeof(nb_color * sizeof(*lpalette)));
/* initialize transparency as complete transparent */
memset(lalpha,0,sizeof(nb_color * sizeof(*lalpha)));
}
if(bitmap)
{
quantize_map(lalpha, luit, lpalette, bitmap, size, 3, nb_color);
}
*palette = lpalette;
*alpha = lalpha;
end:
return ret;
}
static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
png_color *palette, png_byte *alpha, int nb_color)
{
FILE *f = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytep* row_pointer = NULL;
int i, j, ret = 0;
int k = 0;
if(!h)
h = 1;
if(!w)
w = 1;
f = fopen(filename, "wb");
if (!f)
{
mprint("DVB:unable to open %s in write mode \n", filename);
ret = -1;
goto end;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,NULL);
if (!png_ptr)
{
mprint("DVB:unable to create png write struct\n");
goto end;
}
if (!(info_ptr = png_create_info_struct(png_ptr)))
{
mprint("DVB:unable to create png info struct\n");
ret = -1;
goto end;
}
row_pointer = (png_bytep*) malloc(sizeof(png_bytep) * h);
if (!row_pointer)
{
mprint("DVB: unable to allocate row_pointer\n");
ret = -1;
goto end;
}
memset(row_pointer, 0, sizeof(png_bytep) * h);
png_init_io(png_ptr, f);
png_set_IHDR(png_ptr, info_ptr, w, h,
/* bit_depth */8,
PNG_COLOR_TYPE_PALETTE,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_set_PLTE(png_ptr, info_ptr, palette, nb_color);
png_set_tRNS(png_ptr, info_ptr, alpha, nb_color, NULL);
for (i = 0; i < h; i++)
{
row_pointer[i] = (png_byte*) malloc(
png_get_rowbytes(png_ptr, info_ptr));
if (row_pointer[i] == NULL)
break;
}
if (i != h)
{
mprint("DVB: unable to allocate row_pointer internals\n");
ret = -1;
goto end;
}
png_write_info(png_ptr, info_ptr);
for (i = 0; i < h; i++)
{
for (j = 0; j < png_get_rowbytes(png_ptr, info_ptr); j++)
{
if(bitmap)
k = bitmap[i * w + (j)];
else
k = 0;
row_pointer[i][j] = k;
}
}
png_write_image(png_ptr, row_pointer);
png_write_end(png_ptr, info_ptr);
end: if (row_pointer)
{
for (i = 0; i < h; i++)
freep(&row_pointer[i]);
freep(&row_pointer);
}
png_destroy_write_struct(&png_ptr, &info_ptr);
if (f)
fclose(f);
return ret;
}
#endif
#define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
typedef struct DVBSubCLUT
@@ -582,26 +270,20 @@ typedef struct DVBSubContext
{
int composition_id;
int ancillary_id;
int lang_index;
int version;
int time_out;
#ifdef ENABLE_OCR
void *ocr_ctx;
#endif
DVBSubRegion *region_list;
DVBSubCLUT *clut_list;
DVBSubObject *object_list;
DVBSubRegionDisplay *display_list;
DVBSubDisplayDefinition *display_definition;
struct ccx_s_write *out;
long long prev_start;
} DVBSubContext;
typedef struct DVBOutContext
{
long long start_time;
long long end_time;
}DVBOutContext;
static DVBSubObject* get_object(DVBSubContext *ctx, int object_id)
{
DVBSubObject *ptr = ctx->object_list;
@@ -729,124 +411,6 @@ static void delete_regions(DVBSubContext *ctx)
}
}
#ifdef DEBUG
static void save_display_set(DVBSubContext *ctx)
{
DVBSubRegion *region;
DVBSubRegionDisplay *display;
DVBSubCLUT *clut;
int x_pos, y_pos, width, height;
int x, y, y_off, x_off;
uint8_t *pbuf;
char *filename;
void *sp = ctx->out->spupng_data;
x_pos = -1;
y_pos = -1;
width = 0;
height = 0;
for (display = ctx->display_list; display; display = display->next)
{
region = get_region(ctx, display->region_id);
if (x_pos == -1)
{
x_pos = display->x_pos;
y_pos = display->y_pos;
width = region->width;
height = region->height;
}
else
{
if (display->x_pos < x_pos)
{
width += (x_pos - display->x_pos);
x_pos = display->x_pos;
}
if (display->y_pos < y_pos)
{
height += (y_pos - display->y_pos);
y_pos = display->y_pos;
}
if (display->x_pos + region->width > x_pos + width)
{
width = display->x_pos + region->width - x_pos;
}
if (display->y_pos + region->height > y_pos + height)
{
height = display->y_pos + region->height - y_pos;
}
}
}
if (x_pos >= 0)
{
png_color *palette = NULL;
png_byte *alpha = NULL;
#ifdef ENABLE_OCR
char*str = NULL;
#endif
filename = get_spupng_filename(sp);
inc_spupng_fileindex(sp);
set_spupng_offset(sp,y_pos,x_pos);
pbuf = (uint8_t*) malloc(width * height);
memset(pbuf, 0x0, width * height);
for (display = ctx->display_list; display; display = display->next)
{
region = get_region(ctx, display->region_id);
x_off = display->x_pos - x_pos;
y_off = display->y_pos - y_pos;
clut = get_clut(ctx, region->clut);
if (clut == 0)
clut = &default_clut;
for (y = 0; y < region->height; y++)
{
for (x = 0; x < region->width; x++)
{
pbuf[((y + y_off) * width) + x_off + x] =
region->pbuf[y * region->width + x];
}
}
}
pre_process_bitmap(&palette,&alpha,width*height,clut->clut16, clut->ilut16,pbuf,region->depth);
#ifdef ENABLE_OCR
str = ocr_bitmap(palette,alpha,pbuf,width,height);
if(str)
{
write_spucomment(sp,str);
}
#endif
save_spupng(filename, pbuf, width, height, palette, alpha,(1 << region->depth));
free(pbuf);
freep(&palette);
freep(&alpha);
}
else if(!ctx->prev_start)
{
png_color palette = {0,0,0};
png_byte alpha = 0;
filename = get_spupng_filename(sp);
inc_spupng_fileindex(sp);
/* save dummy frame */
save_spupng(filename,NULL,1,1,&palette,&alpha,1);
}
}
#endif
/**
* @param composition_id composition-page_id found in Subtitle descriptors
@@ -859,15 +423,24 @@ static void save_display_set(DVBSubContext *ctx)
* @return DVB context kept as void* for abstraction
*
*/
void* dvbsub_init_decoder(int composition_id, int ancillary_id)
void* dvbsub_init_decoder(struct dvb_config* cfg)
{
int i, r, g, b, a = 0;
DVBSubContext *ctx = (DVBSubContext*) malloc(sizeof(DVBSubContext));
memset(ctx, 0, sizeof(DVBSubContext));
ctx->composition_id = composition_id;
ctx->ancillary_id = ancillary_id;
ctx->composition_id = cfg->composition_id[0];
ctx->ancillary_id = cfg->ancillary_id[0];
ctx->lang_index = cfg->lang_index[0];
#ifdef ENABLE_OCR
ctx->ocr_ctx = init_ocr(ctx->lang_index);
if(!ctx->ocr_ctx)
{
freep(&ctx);
return NULL;
}
#endif
ctx->version = -1;
default_clut.id = -1;
@@ -1738,9 +1311,6 @@ static void dvbsub_parse_page_segment(void *dvb_ctx, const uint8_t *buf,
int page_state;
int timeout;
int version;
long long start = get_visible_start();
void *sp = ctx->out->spupng_data;
if (buf_size < 1)
return;
@@ -1758,19 +1328,6 @@ static void dvbsub_parse_page_segment(void *dvb_ctx, const uint8_t *buf,
ctx->time_out = timeout;
ctx->version = version;
if(ctx->prev_start == 0)
{
write_sputag(sp, ctx->prev_start, start);
save_display_set(ctx);
}
else if(ctx->display_list)
{
write_sputag(sp, ctx->prev_start, start);
save_display_set(ctx);
}
ctx->prev_start = start;
if (page_state == 1 || page_state == 2)
{
delete_regions(ctx);
@@ -1870,25 +1427,53 @@ static void dvbsub_parse_display_definition_segment(void *dvb_ctx,
}
}
static int dvbsub_display_end_segment(void *dvb_ctx, const uint8_t *buf,
int buf_size)
static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
{
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
DVBSubRegion *region;
DVBSubRegionDisplay *display;
DVBSubCLUT *clut;
int i;
DVBSubDisplayDefinition *display_def = ctx->display_definition;
struct cc_bitmap *rect = NULL;
uint32_t *clut_table;
int offset_x=0, offset_y=0;
int ret = 0;
sub->type = CC_BITMAP;
sub->lang_index = ctx->lang_index;
if (display_def)
{
offset_x = display_def->x;
offset_y = display_def->y;
}
for (display = ctx->display_list; display; display = display->next)
{
region = get_region(ctx, display->region_id);
if (region && region->dirty)
sub->nb_data++;
}
if( sub->nb_data <= 0 )
{
return 0;
}
i = 0;
rect = malloc( sizeof(struct cc_bitmap) * sub->nb_data);
if(!rect)
{
return -1;
}
sub->start_time = get_visible_start();
sub->end_time = sub->start_time + ( ctx->time_out * 1000 );
sub->flags |= SUB_EOD_MARKER;
sub->got_output = 1;
sub->data = rect;
for (display = ctx->display_list; display; display = display->next)
{
#ifdef ENABLE_OCR
char *ocr_str = NULL;
#endif
region = get_region(ctx, display->region_id);
if (!region)
@@ -1896,52 +1481,84 @@ static int dvbsub_display_end_segment(void *dvb_ctx, const uint8_t *buf,
if (!region->dirty)
continue;
rect->x = display->x_pos + offset_x;
rect->y = display->y_pos + offset_y;
rect->w = region->width;
rect->h = region->height;
rect->nb_colors = (1 << region->depth);
rect->linesize[0] = region->width;
clut = get_clut(ctx, region->clut);
if (!clut)
clut = &default_clut;
i++;
switch (region->depth)
{
case 2:
clut_table = clut->clut4;
case 8:
clut_table = clut->clut256;
break;
case 4:
default:
clut_table = clut->clut16;
break;
}
rect->data[1] = malloc(1024);
memset(rect->data[1], 0, 1024);
memcpy(rect->data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
rect->data[0] = malloc(region->buf_size);
memcpy(rect->data[0], region->pbuf, region->buf_size);
#ifdef ENABLE_OCR
ret = ocr_rect(ctx->ocr_ctx, rect, &ocr_str);
if(ret >= 0)
rect->ocr_text = ocr_str;
#endif
rect++;
}
#ifdef DEBUG
#ifdef DeBUG
if (ctx->object_list)
{
//save_display_set(ctx);
}
#endif
return 1;
return 0;
}
/**
* @param dvb_ctx PreInitialized DVB context using DVB
* @param data output subtitle data, to be implemented
* @param data_size Output subtitle data size. pass the pointer to an integer, NOT to be NULL.
* @param buf buffer containing segment data, first sync byte need to 0x0f.
* does not include data_identifier and subtitle_stream_id.
* @param buf_size size of buf buffer
* @param sub output subtitle data
*
* @return -1 on error
*/
int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
const unsigned char *buf, int buf_size)
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub)
{
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
const uint8_t *p, *p_end;
int segment_type;
int page_id;
int segment_length;
int ret;
int ret = 0;
int got_segment = 0;
if (buf_size <= 6 || *buf != 0x0f)
{
mprint("incomplete or broken packet");
mprint("incomplete or broken packet\n");
return -1;
}
p = buf;
p_end = buf + buf_size;
set_fts();
while (p_end - p >= 6 && *p == 0x0f)
{
p += 1;
@@ -1953,7 +1570,7 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
if (p_end - p < segment_length)
{
mprint("incomplete or broken packet");
mprint("incomplete or broken packet\n");
return -1;
}
@@ -1973,7 +1590,7 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
case DVBSUB_CLUT_SEGMENT:
ret = dvbsub_parse_clut_segment(dvb_ctx, p, segment_length);
if (ret < 0)
return ret;
goto end;
got_segment |= 4;
break;
case DVBSUB_OBJECT_SEGMENT:
@@ -1985,8 +1602,7 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
segment_length);
break;
case DVBSUB_DISPLAY_SEGMENT:
*data_size = dvbsub_display_end_segment(dvb_ctx, p,
segment_length);
write_dvb_sub(dvb_ctx,sub);
got_segment |= 16;
break;
default:
@@ -2002,11 +1618,15 @@ int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
// segments then we need no further data.
if (got_segment == 15)
{
*data_size = dvbsub_display_end_segment(dvb_ctx, p, 0);
write_dvb_sub(dvb_ctx,sub);
}
end:
if ( ret >= 0 )
ret = p - buf;
return p - buf;
return ret;
}
/**
* @func parse_dvb_description
@@ -2051,9 +1671,9 @@ int parse_dvb_description(struct dvb_config* cfg, unsigned char*data,
for (i = 0; i < cfg->n_language; i++, data += i * 8)
{
/* setting language to undefined if not found in language lkup table */
for (j = 0, cfg->lang_index[i] = 0; dvb_language[j] != NULL; j++)
for (j = 0, cfg->lang_index[i] = 0; language[j] != NULL; j++)
{
if (!strncmp((const char*) (data), dvb_language[j], 3))
if (!strncmp((const char*) (data), language[j], 3))
cfg->lang_index[i] = j;
}
cfg->sub_type[i] = data[3];
@@ -2064,17 +1684,3 @@ int parse_dvb_description(struct dvb_config* cfg, unsigned char*data,
return 0;
}
/*
* @func dvbsub_set_write the output structure in dvb
* set ccx_s_write structure in dvb_ctx
*
* @param dvb_ctx context of dvb which was returned by dvbsub_init_decoder
*
* @param out output context returned by init_write
*
*/
void dvbsub_set_write(void *dvb_ctx, struct ccx_s_write *out)
{
DVBSubContext *ctx = (DVBSubContext *) dvb_ctx;
ctx->out = out;
}

View File

@@ -18,7 +18,7 @@
#define MAX_LANGUAGE_PER_DESC 5
#include "ccextractor.h"
#include "lib_ccx.h"
#ifdef __cplusplus
extern "C"
{
@@ -37,32 +37,26 @@ struct dvb_config
};
/**
* @param composition_id composition-page_id found in Subtitle descriptors
* associated with subtitle stream in the PMT
* it could be -1 if not found in PMT.
* @param ancillary_id ancillary-page_id found in Subtitle descriptors
* associated with subtitle stream in the PMT.
* it could be -1 if not found in PMT.
* @param cfg Structure containg configuration
*
* @return DVB context kept as void* for abstraction
*
*/
void* dvbsub_init_decoder(int composition_id, int ancillary_id);
void* dvbsub_init_decoder(struct dvb_config* cfg);
int dvbsub_close_decoder(void *dvb_ctx);
/**
* @param dvb_ctx PreInitialized DVB context using DVB
* @param data output subtitle data, to be implemented
* @param data_size Output subtitle data size. pass the pointer to an intiger, NOT to be NULL.
* @param buf buffer containg segment data, first sync byte needto 0x0f.
* @param buf buffer containing segment data, first sync byte need to 0x0f.
* does not include data_identifier and subtitle_stream_id.
* @param buf_size size of buf buffer
* @param sub output subtitle data
*
* @return -1 on error
*/
int dvbsub_decode(void *dvb_ctx, void *data, int *data_size,
const unsigned char *buf, int buf_size);
int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct cc_subtitle *sub);
/**
* @func parse_dvb_description
*
@@ -82,8 +76,8 @@ int parse_dvb_description(struct dvb_config* cfg, unsigned char*data,
*
* @param dvb_ctx context of dvb which was returned by dvbsub_init_decoder
*
* @param out output context returned by init_write
*
* @param out output context returned by init_write
*
*/
void dvbsub_set_write(void *dvb_ctx, struct ccx_s_write *out);

View File

@@ -1,5 +1,5 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
// Functions to parse a mpeg-2 data stream, see ISO/IEC 13818-2 6.2
static int no_bitstream_error = 0;
@@ -20,24 +20,24 @@ 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 bitstream *esstream);
static int read_seq_info(struct bitstream *esstream);
static int sequence_header(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 bitstream *esstream);
static int gop_header(struct bitstream *esstream);
static int read_pic_info(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 bitstream *esstream, int udtype);
static int extension_and_user_data(struct bitstream *esstream, int udtype);
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 read_pic_data(struct bitstream *esstream);
/* 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 (unsigned char *data, LLONG length)
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG length,struct cc_subtitle *sub)
{
if (length<8) // Need to look ahead 8 bytes
return length;
@@ -48,7 +48,7 @@ LLONG process_m2v (unsigned char *data, LLONG length)
// Process data. The return value is ignored as esstream.pos holds
// the information how far the parsing progressed.
es_video_sequence(&esstream);
es_video_sequence(ctx, &esstream, sub);
// This returns how many bytes were processed and can therefore
// be discarded from "buffer". "esstream.pos" points to the next byte
@@ -185,7 +185,7 @@ 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 bitstream *esstream)
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
// Avoid "Skip forward" message on first call and later only
// once per search.
@@ -260,7 +260,7 @@ static int es_video_sequence(struct bitstream *esstream)
if (!in_pic_data && startcode == 0xB3)
{
if (!read_seq_info(esstream))
if (!read_seq_info(ctx, esstream))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -272,7 +272,7 @@ static int es_video_sequence(struct bitstream *esstream)
if (!in_pic_data && startcode == 0xB8)
{
if (!read_gop_info(esstream))
if (!read_gop_info(ctx, esstream,sub))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -284,7 +284,7 @@ static int es_video_sequence(struct bitstream *esstream)
if (!in_pic_data && startcode == 0x00)
{
if (!read_pic_info(esstream))
if (!read_pic_info(ctx, esstream, sub))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -300,7 +300,7 @@ static int es_video_sequence(struct bitstream *esstream)
// This check needs to be before the "in_pic_data" part.
if ( saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
{
if (!read_eau_info(esstream, saw_seqgoppic-1))
if (!read_eau_info(ctx, esstream, saw_seqgoppic-1, sub))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -345,20 +345,20 @@ static int es_video_sequence(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 bitstream *esstream)
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Read Sequence Info\n");
// We only get here after seeing that start code
if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
fatal(EXIT_BUG_BUG, "read_seq_info: Impossible!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "read_seq_info: Impossible!");
// If we get here esstream points to the start of a sequence_header_code
// should we run out of data in esstream this is where we want to restart
// after getting more.
unsigned char *video_seq_start = esstream->pos;
sequence_header(esstream);
sequence_header(ctx, esstream);
sequence_ext(esstream);
// FIXME: if sequence extension is missing this is not MPEG-2,
// or broken. Set bitstream error.
@@ -382,7 +382,7 @@ static int read_seq_info(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 bitstream *esstream)
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
{
dbg_print(CCX_DMT_VERBOSE, "Sequence header\n");
@@ -391,17 +391,17 @@ static int sequence_header(struct bitstream *esstream)
// We only get here after seeing that start code
if (read_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
fatal(EXIT_BUG_BUG, "Impossible!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
unsigned hor_size = (unsigned) read_bits(esstream,12);
unsigned vert_size = (unsigned) read_bits(esstream,12);
unsigned aspect_ratio = (unsigned) read_bits(esstream,4);
unsigned frame_rate = (unsigned) read_bits(esstream,4);
file_report.width = hor_size;
file_report.height = vert_size;
file_report.aspect_ratio = aspect_ratio;
file_report.frame_rate = frame_rate;
ctx->freport.width = hor_size;
ctx->freport.height = vert_size;
ctx->freport.aspect_ratio = aspect_ratio;
ctx->freport.frame_rate = frame_rate;
// Discard some information
read_bits(esstream, 18+1+10+1);
@@ -425,9 +425,10 @@ static int sequence_header(struct bitstream *esstream)
// If horizontal/vertical size, framerate and/or aspect
// ratio are ilegal, we discard the
// whole sequence info.
if (vert_size >= 288 && vert_size <= 1088 &&
if (vert_size >= 288 && vert_size <= 1088 &&
hor_size >= 352 && hor_size <= 1920 &&
hor_size / vert_size >= 352/576 && hor_size / vert_size <= 2 &&
(hor_size*100) / vert_size >= (352*100)/576 && // The weird *100 is to avoid using floats
hor_size / vert_size <= 2 &&
frame_rate>0 && frame_rate<9 &&
aspect_ratio>0 && aspect_ratio<5)
{
@@ -438,7 +439,7 @@ static int sequence_header(struct bitstream *esstream)
/ MPEG_CLOCK_FREQ);
mprint (" at %02u:%02u",cur_sec/60, cur_sec % 60);
}
mprint ("\n");
mprint ("\n");
mprint ("[%u * %u] [AR: %s] [FR: %s]",
hor_size,vert_size,
aspect_ratio_types[aspect_ratio],
@@ -455,8 +456,8 @@ static int sequence_header(struct bitstream *esstream)
activity_video_info (hor_size,vert_size,
aspect_ratio_types[aspect_ratio],
framerates_types[frame_rate]);
}
else
}
else
{
dbg_print(CCX_DMT_VERBOSE, "\nInvalid sequence header:\n");
dbg_print(CCX_DMT_VERBOSE, "V: %u H: %u FR: %u AS: %u\n",
@@ -527,20 +528,20 @@ 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 bitstream *esstream)
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info\n");
// We only get here after seeing that start code
if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
fatal(EXIT_BUG_BUG, "Impossible!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
// If we get here esstream points to the start of a group_start_code
// should we run out of data in esstream this is where we want to restart
// after getting more.
unsigned char *gop_info_start = esstream->pos;
gop_header(esstream);
gop_header(ctx, esstream, sub);
//extension_and_user_data(esstream);
if (esstream->error)
@@ -561,7 +562,7 @@ static int read_gop_info(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 gop_header(struct bitstream *esstream)
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "GOP header\n");
@@ -570,7 +571,7 @@ static int gop_header(struct bitstream *esstream)
// We only get here after seeing that start code
if (read_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
fatal(EXIT_BUG_BUG, "Impossible!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
unsigned drop_frame_flag = (unsigned) read_bits(esstream,1);
struct gop_time_code gtc;
@@ -594,7 +595,7 @@ static int gop_header(struct bitstream *esstream)
// Flush buffered cc blocks before doing the housekeeping
if (has_ccdata_buffered)
{
process_hdcc();
process_hdcc(ctx, sub);
}
// Last GOPs pulldown frames
@@ -612,19 +613,19 @@ static int gop_header(struct bitstream *esstream)
// are 20% or more deviation.
if ( (ccx_options.debug_mask & CCX_DMT_TIME)
&& ((gtc.ms - gop_time.ms // more than 20% longer
> frames_since_last_gop*1000.0/current_fps*1.2)
> ctx->frames_since_last_gop*1000.0/current_fps*1.2)
||
(gtc.ms - gop_time.ms // or 20% shorter
< frames_since_last_gop*1000.0/current_fps*0.8))
< ctx->frames_since_last_gop*1000.0/current_fps*0.8))
&& first_gop_time.inited )
{
mprint("\rWarning: Jump in GOP timing.\n");
mprint(" (old) %s",
print_mstime(gop_time.ms));
mprint(" + %s (%uF)",
print_mstime((LLONG) (frames_since_last_gop
print_mstime((LLONG) (ctx->frames_since_last_gop
*1000.0/current_fps)),
frames_since_last_gop);
ctx->frames_since_last_gop);
mprint(" != (new) %s\n",
print_mstime(gtc.ms));
}
@@ -657,9 +658,9 @@ static int gop_header(struct bitstream *esstream)
gop_time = gtc;
frames_since_last_gop=0;
ctx->frames_since_last_gop=0;
// Indicate that we read a gop header (since last frame number 0)
saw_gop_header = 1;
ctx->saw_gop_header = 1;
// If we use GOP timing, reconstruct the PTS from the GOP
if (ccx_options.use_gop_as_pts==1)
@@ -698,13 +699,13 @@ static int gop_header(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_pic_info(struct bitstream *esstream)
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info\n");
// We only get here after seeing that start code
if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100)
fatal(EXIT_BUG_BUG, "Impossible!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
// If we get here esstream points to the start of a group_start_code
// should we run out of data in esstream this is where we want to restart
@@ -729,18 +730,18 @@ static int read_pic_info(struct bitstream *esstream)
// 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 (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
// (temporal_reference != current_tref))
// {
{
if (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
(temporal_reference != 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)
{
process_hdcc();
process_hdcc(ctx, sub);
}
anchor_hdcc(temporal_reference);
// }
}
}
current_tref = temporal_reference;
@@ -758,7 +759,7 @@ static int read_pic_info(struct bitstream *esstream)
(unsigned) (current_pts), temporal_reference,
pict_types[picture_coding_type],
(unsigned) (frames_since_ref_time),
(unsigned) (frames_since_last_gop));
(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()));
@@ -772,16 +773,16 @@ static int read_pic_info(struct bitstream *esstream)
// the beginning of the GOP, otherwise it is now.
if(temporal_reference == 0)
{
last_gop_length = maxtref + 1;
ctx->last_gop_length = maxtref + 1;
maxtref = temporal_reference;
// frames_since_ref_time is used in set_fts()
if( saw_gop_header )
if( ctx->saw_gop_header )
{
// This time (fts_at_gop_start) that was set in the
// GOP header and it might be off by one GOP. See the comment there.
frames_since_ref_time = frames_since_last_gop; // Should this be 0?
frames_since_ref_time = ctx->frames_since_last_gop; // Should this be 0?
}
else
{
@@ -796,39 +797,39 @@ static int read_pic_info(struct bitstream *esstream)
print_debug_timing();
}
saw_gop_header = 0; // Reset the value
ctx->saw_gop_header = 0; // Reset the value
}
if ( !saw_gop_header && picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
if ( !ctx->saw_gop_header && 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
frames_since_last_gop = 0;
ctx->frames_since_last_gop = 0;
}
// Set maxtref
if( temporal_reference > maxtref ) {
maxtref = temporal_reference;
if (maxtref+1 > max_gop_length)
max_gop_length = maxtref+1;
if (maxtref+1 > ctx->max_gop_length)
ctx->max_gop_length = maxtref+1;
}
unsigned extraframe = 0;
if (repeat_first_field)
{
pulldownfields++;
total_pulldownfields++;
if ( current_progressive_sequence || !(total_pulldownfields%2) )
ctx->total_pulldownfields++;
if ( current_progressive_sequence || !(ctx->total_pulldownfields%2) )
extraframe = 1;
if ( current_progressive_sequence && top_field_first )
extraframe = 2;
dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
total_pulldownfields, extraframe);
ctx->total_pulldownfields, extraframe);
}
total_pulldownframes += extraframe;
ctx->total_pulldownframes += extraframe;
total_frames_count += 1+extraframe;
frames_since_last_gop += 1+extraframe;
ctx->frames_since_last_gop += 1+extraframe;
frames_since_ref_time += 1+extraframe;
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info - processed\n\n");
@@ -849,7 +850,7 @@ static int pic_header(struct bitstream *esstream)
// We only get here after seeing that start code
if (read_u32(esstream) != 0x00010000) // LSB first (0x00000100)
fatal(EXIT_BUG_BUG, "Impossible!");
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);
@@ -945,7 +946,7 @@ 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 bitstream *esstream, int udtype)
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info\n");
@@ -953,13 +954,13 @@ static int read_eau_info(struct bitstream *esstream, int udtype)
unsigned char *tst = next_bytes(esstream, 4);
if (!tst || tst[0]!=0x00 || tst[1]!=0x00 || tst[2]!=0x01
|| (tst[3]!=0xB2 && tst[3]!=0xB5) ) // (0x000001 B2||B5)
fatal(EXIT_BUG_BUG, "Impossible!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible!");
// The following extension_and_user_data() function makes sure that
// user data is not evaluated twice. Should the function run out of
// data it will make sure that esstream points to where we want to
// continue after getting more.
if( !extension_and_user_data(esstream, udtype) )
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");
@@ -978,7 +979,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype)
// 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 bitstream *esstream, int udtype)
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "Extension and user data(%d)\n", udtype);
@@ -1002,7 +1003,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype)
// Advanve esstream to the next startcode. Verify that
// the whole extension was available and discard blocks
// followed by PACK headers. The latter usually indicates
// a PS treated as an ES.
// a PS treated as an ES.
uint8_t nextstartcode = search_start_code(esstream);
if (nextstartcode == 0xBA)
{
@@ -1030,7 +1031,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype)
{
struct bitstream ustream;
init_bitstream(&ustream, dstart, esstream->pos);
user_data(&ustream, udtype);
user_data(ctx, &ustream, udtype, sub);
}
else
{

View File

@@ -1,4 +1,4 @@
#include "ccextractor.h"
#include "lib_ccx.h"
// Parse the user data for captions. The udtype variable denotes
@@ -9,8 +9,10 @@
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if ustream->error
// is FALSE, parsing can set ustream->error to TRUE.
int user_data(struct bitstream *ustream, int udtype)
int user_data(struct lib_ccx_ctx *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
@@ -19,26 +21,26 @@ int user_data(struct bitstream *ustream, int udtype)
// ustream->error=1;
return 0; // Actually discarded on call.
// CFS: Seen in a Wobble edited file.
// fatal(EXIT_BUG_BUG, "user_data: Impossible!");
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
}
// Do something
stat_numuserheaders++;
ctx->stat_numuserheaders++;
//header+=4;
unsigned char *ud_header = next_bytes(ustream, 4);
if (ustream->error || ustream->bitsleft <= 0)
{
{
return 0; // Actually discarded on call.
// CFS: Seen in Stick_VHS.mpg.
// fatal(EXIT_BUG_BUG, "user_data: Impossible!");
// CFS: Seen in Stick_VHS.mpg.
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
}
// DVD CC header, see
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
{
stat_dvdccheaders++;
ctx->stat_dvdccheaders++;
// Probably unneeded, but keep looking for extra caption blocks
int maybeextracb = 1;
@@ -51,7 +53,7 @@ int user_data(struct bitstream *ustream, int udtype)
int truncate_flag = (int) read_bits(ustream,1); // truncate_flag - one CB extra
int field1packet = 0; // expect Field 1 first
if (pattern_flag == 0x00)
if (pattern_flag == 0x00)
field1packet=1; // expect Field 1 second
dbg_print(CCX_DMT_VERBOSE, "Reading %d%s DVD CC segments\n",
@@ -87,12 +89,12 @@ int user_data(struct bitstream *ustream, int udtype)
with marker bytes of \xff and \xfe
Since markers can be repeated, use pattern as well */
if ((data[0]&0xFE) == 0xFE) // Check if valid
{
{
if (data[0]==0xff && j==field1packet)
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(data);
do_cb(dec_ctx, data, sub);
rcbcount++;
}
else
@@ -118,12 +120,12 @@ int user_data(struct bitstream *ustream, int udtype)
with marker bytes of \xff and \xfe
Since markers can be repeated, use pattern as well */
if ((data[0]&0xFE) == 0xFE) // Check if valid
{
{
if (data[0]==0xff && j==field1packet)
data[0]=0x04; // Field 1
else
data[0]=0x05; // Field 2
do_cb(data);
do_cb(dec_ctx, data, sub);
ecbcount++;
}
else
@@ -144,7 +146,7 @@ int user_data(struct bitstream *ustream, int udtype)
{
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
stat_scte20ccheaders++;
ctx->stat_scte20ccheaders++;
read_bytes(ustream, 2); // "03 01"
unsigned cc_count = (unsigned int) read_bits(ustream,5);
@@ -164,7 +166,7 @@ int user_data(struct bitstream *ustream, int udtype)
/* marker = (unsigned int)read_bits(ustream,1); // TODO: Add syntax check */
if (ustream->bitsleft < 0)
fatal(EXIT_BUG_BUG, "Oops!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Oops!");
// Field_number is either
// 0 .. forbiden
@@ -192,7 +194,7 @@ int user_data(struct bitstream *ustream, int udtype)
}
}
cc_data[cc_count*3]=0xFF;
store_hdcc(cc_data, cc_count, current_tref, fts_now);
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
}
@@ -200,31 +202,31 @@ int user_data(struct bitstream *ustream, int udtype)
}
// ReplayTV 4000/5000 caption header - parsing information
// derived from CCExtract.bdl
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|| ud_header[0] == 0x99) //ReplayTV 5000
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|| ud_header[0] == 0x99) //ReplayTV 5000
&& ud_header[1] == 0x02 )
{
unsigned char data[3];
if (ud_header[0]==0xbb)
stat_replay4000headers++;
ctx->stat_replay4000headers++;
else
stat_replay5000headers++;
ctx->stat_replay5000headers++;
read_bytes(ustream, 2); // "BB 02" or "99 02"
data[0]=0x05; // Field 2
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(data);
do_cb(dec_ctx, data, sub);
read_bytes(ustream, 2); // Skip "CC 02" for R4000 or "AA 02" for R5000
data[0]=0x04; // Field 1
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(data);
do_cb(dec_ctx, data, sub);
}
// HDTV - see A/53 Part 4 (Video)
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
{
stat_hdtv++;
ctx->stat_hdtv++;
read_bytes(ustream, 4); // "47 41 39 34"
@@ -243,7 +245,7 @@ int user_data(struct bitstream *ustream, int udtype)
int proceed = 1;
unsigned char *cc_data = read_bytes(ustream, cc_count*3);
if (ustream->bitsleft < 0)
fatal(EXIT_BUG_BUG, "Not enough for CC captions!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Not enough for CC captions!");
// Check for proper marker - This read makes sure that
// cc_count*3+1 bytes are read and available in cc_data.
@@ -264,7 +266,7 @@ int user_data(struct bitstream *ustream, int udtype)
// Please note we store the current value of the global
// fts_now variable (and not get_fts()) as we are going to
// re-create the timeline in process_hdcc() (Slightly ugly).
store_hdcc(cc_data, cc_count, current_tref, fts_now);
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
}
@@ -285,7 +287,7 @@ int user_data(struct bitstream *ustream, int udtype)
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
stat_dishheaders++;
ctx->stat_dishheaders++;
read_bytes(ustream, 2); // "05 02"
@@ -344,7 +346,7 @@ int user_data(struct bitstream *ustream, int udtype)
dishdata[cc_count*3] = 0xFF; // Set end marker
store_hdcc(dishdata, cc_count, current_tref, fts_now);
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
// Ignore 3 (0x0A, followed by two unknown) bytes.
break;
@@ -360,7 +362,7 @@ int user_data(struct bitstream *ustream, int udtype)
cc_count = 2;
dishdata[1]=dcd[1];
dishdata[2]=dcd[2];
dishdata[3]=0x04; // Field 1
dishdata[4]=dcd[3];
dishdata[5]=dcd[4];
@@ -368,8 +370,8 @@ int user_data(struct bitstream *ustream, int udtype)
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
store_hdcc(dishdata, cc_count, current_tref, fts_now);
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
// Ignore 4 (0x020A, followed by two unknown) bytes.
break;
@@ -379,7 +381,7 @@ int user_data(struct bitstream *ustream, int udtype)
// 0 : 0x04
// - the following are from previous 0x05 caption header -
// 1 : prev dcd[2]
// 2-3: prev dcd[3-4]
// 2-3: prev dcd[3-4]
// 4-5: prev dcd[5-6]
dbg_print(CCX_DMT_PARSE, " - %02X pch: %02X %5u %02X:%02X\n",
dcd[0], dcd[1],
@@ -429,13 +431,13 @@ int user_data(struct bitstream *ustream, int udtype)
dishdata[4]=dcd[0];
dishdata[5]=dcd[1];
dishdata[6] = 0xFF; // Set end marker
dbg_print(CCX_DMT_PARSE, ":%s", debug_608toASC( dishdata, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
}
store_hdcc(dishdata, cc_count, current_tref, fts_now);
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
break;
default:
@@ -450,7 +452,7 @@ int user_data(struct bitstream *ustream, int udtype)
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
{
// Either a documentation or more examples are needed.
stat_divicom++;
ctx->stat_divicom++;
unsigned char data[3];
@@ -460,7 +462,7 @@ int user_data(struct bitstream *ustream, int udtype)
data[0]=0x04; // Field 1
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(data);
do_cb(dec_ctx, data, sub);
// This is probably incomplete!
}
else

187
src/lib_ccx/ffmpeg_intgr.c Normal file
View File

@@ -0,0 +1,187 @@
#include "ffmpeg_intgr.h"
#ifdef ENABLE_FFMPEG
#include <libavformat/avformat.h>
#include <libavfilter/avfiltergraph.h>
#include <libavfilter/avcodec.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/avstring.h>
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
#include <libavutil/audio_fifo.h>
#include <libavutil/log.h>
#include <libavutil/error.h>
#include "lib_ccx.h"
struct ffmpeg_ctx
{
AVFormatContext *ifmt;
AVCodecContext *dec_ctx;
AVFrame *frame;
int stream_index;
};
/**
* call back function to be registered for avlog
*/
static void log_cb(void* ptr, int level, const char* fmt, va_list vl)
{
if (level > av_log_get_level())
return;
const char*name = NULL;
FILE *flog;
if (ccx_options.messages_target==CCX_MESSAGES_STDOUT)
flog = stdout;
else
flog = stderr;
if (level == AV_LOG_PANIC)
fprintf(flog, "[panic][%s] ", name);
else if (level == AV_LOG_FATAL)
fprintf(flog, "[fatal][%s] ", name);
else if (level == AV_LOG_ERROR)
fprintf(flog, "[error][%s] ", name);
else if (level == AV_LOG_WARNING)
fprintf(flog, "[warning][%s] ", name);
else if (level == AV_LOG_INFO)
fprintf(flog, "[info][%s] ", name);
else if (level == AV_LOG_DEBUG)
fprintf(flog, "[debug][%s] ", name);
vfprintf(flog, fmt, vl);
}
/**
* @path this path could be relative or absolute path of static file
* this path could be path of device
*
* @return ctx Context of ffmpeg
*/
void *init_ffmpeg(char *path)
{
int ret = 0;
int stream_index = 0;
struct ffmpeg_ctx *ctx;
AVCodec *dec = NULL;
avcodec_register_all();
av_register_all();
if(ccx_options.debug_mask & CCX_DMT_VERBOSE)
av_log_set_level(AV_LOG_INFO);
else if (ccx_options.messages_target == 0)
av_log_set_level(AV_LOG_FATAL);
av_log_set_callback(log_cb);
ctx = av_mallocz(sizeof(*ctx));
if(!ctx)
{
av_log(NULL,AV_LOG_ERROR,"Not enough memory\n");
return NULL;
}
/**
* Initialize decoder according to the name of input
*/
ret = avformat_open_input(&ctx->ifmt, path, NULL, NULL);
if(ret < 0)
{
av_log(NULL,AV_LOG_ERROR,"could not open input(%s) format\n",path);
goto fail;
}
ret = avformat_find_stream_info(ctx->ifmt,NULL);
if(ret < 0)
{
av_log(NULL,AV_LOG_ERROR,"could not find any stream\n");
goto fail;
}
/* first search in strean if not found search the video stream */
ret = av_find_best_stream(ctx->ifmt, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "no suitable subtitle or caption\n");
goto fail;
}
stream_index = ret;
ctx->dec_ctx = ctx->ifmt->streams[stream_index]->codec;
ctx->stream_index = stream_index;
ret = avcodec_open2(ctx->dec_ctx, dec, NULL);
if(ret < 0)
{
av_log(NULL,AV_LOG_ERROR,"unable to open codec\n");
goto fail;
}
//Initialize frame where input frame will be stored
ctx->frame = av_frame_alloc();
fail:
return ctx;
}
/**
* @param ctx context of ffmpeg
* @param data preallocated buffer where data will be recieved
* @param maxlen length of buffer, where data will be copied
* @return number of bytes recieved as data
*/
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen)
{
struct ffmpeg_ctx *ctx = arg;
int len = 0;
int ret = 0;
int got_frame;
AVPacket packet;
ret = av_read_frame(ctx->ifmt, &packet);
if(ret == AVERROR_EOF)
{
return ret;
}
else if(ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "not able to read the packet\n");
return ret;
}
else if(packet.stream_index != ctx->stream_index)
{
return AVERROR(EAGAIN);
}
ret = avcodec_decode_video2(ctx->dec_ctx,ctx->frame, &got_frame,&packet);
if(ret < 0)
{
av_log(NULL,AV_LOG_ERROR,"unable to decode packet\n");
}
else if (!got_frame)
{
return AVERROR(EAGAIN);
}
current_pts = av_frame_get_best_effort_timestamp(ctx->frame);
if(!pts_set)
pts_set = 1;
set_fts();
for(int i = 0;i< ctx->frame->nb_side_data;i++)
{
if(ctx->frame->side_data[i]->type == AV_FRAME_DATA_A53_CC)
{
ctx->frame->pts = av_frame_get_best_effort_timestamp(ctx->frame);
if(ctx->frame->side_data[i]->size > maxlen)
av_log(NULL,AV_LOG_ERROR,"Please consider increasing length of data\n");
else
{
memcpy(data,ctx->frame->side_data[i]->data,ctx->frame->side_data[i]->size);
len = ctx->frame->side_data[i]->size;
}
}
}
if(ret < 0)
return ret;
return len;
}
#endif

View File

@@ -0,0 +1,23 @@
#ifndef _FFMPEG_INTIGRATION
#define _FFMPEG_INTIGRATION
#ifdef ENABLE_FFMPEG
#include "libavutil/common.h"
#include "libavutil/error.h"
#endif
/**
* @path this path could be relative or absolute path of static file
* this path could be path of device
*
* @return ctx Context of ffmpeg
*/
void *init_ffmpeg(char *path);
/**
* @param ctx context of ffmpeg
* @param data preallocated buffer where data will be recieved
* @param maxlen length of buffer, where data will be copied
* @return number of bytes recieved as data
*/
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen);
#endif

View File

@@ -1,5 +1,5 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.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);
@@ -10,28 +10,35 @@ LLONG buffered_read_opt_file (unsigned char *buffer, unsigned int bytes);
LLONG getfilesize (int in)
{
LLONG current=LSEEK (in, 0, SEEK_CUR);
LLONG length = LSEEK (in,0,SEEK_END);
LSEEK (in,current,SEEK_SET);
return length;
int ret = 0;
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;
}
LLONG gettotalfilessize (void) // -1 if one or more files failed to open
LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files failed to open
{
LLONG ts=0;
int h;
for (int i=0;i<num_input_files;i++)
for (int i=0;i<ctx->num_input_files;i++)
{
if (0 == strcmp(inputfile[i],"-")) // Skip stdin
continue;
if (0 == strcmp(ctx->inputfile[i],"-")) // Skip stdin
continue;
#ifdef _WIN32
h=OPEN (inputfile[i],O_RDONLY | O_BINARY);
h=OPEN (ctx->inputfile[i],O_RDONLY | O_BINARY);
#else
h=OPEN (inputfile[i],O_RDONLY);
h=OPEN (ctx->inputfile[i],O_RDONLY);
#endif
if (h==-1)
{
mprint ("\rUnable to open %s\r\n",inputfile[i]);
mprint ("\rUnable to open %s\r\n",ctx->inputfile[i]);
return -1;
}
if (!ccx_options.live_stream)
@@ -41,208 +48,185 @@ LLONG gettotalfilessize (void) // -1 if one or more files failed to open
return ts;
}
void prepare_for_new_file (void)
void prepare_for_new_file (struct lib_ccx_ctx *ctx)
{
// Init per file variables
min_pts=0x01FFFFFFFFLL; // 33 bit
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()
last_reported_progress=-1;
stat_numuserheaders = 0;
stat_dvdccheaders = 0;
stat_scte20ccheaders = 0;
stat_replay5000headers = 0;
stat_replay4000headers = 0;
stat_dishheaders = 0;
stat_hdtv = 0;
stat_divicom = 0;
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;
total_pulldownfields = 0;
total_pulldownframes = 0;
cc_stats[0]=0; cc_stats[1]=0; cc_stats[2]=0; cc_stats[3]=0;
false_pict_header=0;
frames_since_last_gop=0;
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;
saw_caption_block=0;
past=0;
dec_ctx->saw_caption_block=0;
ctx->past=0;
pts_big_change=0;
startbytes_pos=0;
startbytes_avail=0;
ctx->startbytes_pos=0;
ctx->startbytes_avail=0;
init_file_buffer();
anchor_hdcc(-1);
firstcall = 1;
for(int x=0; x<0xfff; x++) {
ctx->epg_buffers[x].buffer=NULL;
ctx->epg_buffers[x].ccounter=0;
}
for (int i = 0; i < TS_PMT_MAP_SIZE; i++) {
ctx->eit_programs[i].array_len=0;
ctx->eit_current_events[i]=-1;
}
ctx->epg_last_output=-1;
ctx->epg_last_live_output=-1;
}
/* Close input file if there is one and let the GUI know */
void close_input_file (void)
void close_input_file (struct lib_ccx_ctx *ctx)
{
if (infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
if (ctx->infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
{
close (infd);
infd=-1;
activity_input_file_closed();
close (ctx->infd);
ctx->infd=-1;
activity_input_file_closed();
}
}
int init_sockets (void)
{
static int socket_inited=0;
if (!socket_inited)
{
#ifdef _WIN32
WSADATA wsaData = {0};
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
wprintf(L"WSAStartup failed: %d\n", iResult);
return 1;
}
#endif
socket_inited=1;
}
return 0;
}
/* Close current file and open next one in list -if any- */
/* bytesinbuffer is the number of bytes read (in some buffer) that haven't been added
to 'past' yet. We provide this number to switch_to_next_file() so a final sanity check
can be done */
int switch_to_next_file (LLONG bytesinbuffer)
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer)
{
if (current_file==-1 || !ccx_options.binary_concat)
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
if (ctx->current_file==-1 || !ccx_options.binary_concat)
{
memset (PIDs_seen,0,65536*sizeof (int));
memset (PIDs_programs,0,65536*sizeof (struct PMT_entry *));
memset (ctx->PIDs_seen,0,65536*sizeof (int));
memset (ctx->PIDs_programs,0,65536*sizeof (struct PMT_entry *));
}
if (ccx_options.input_source==CCX_DS_STDIN)
{
if (infd!=-1) // Means we had already processed stdin. So we're done.
if (ctx->infd!=-1) // Means we had already processed stdin. So we're done.
{
if (ccx_options.print_file_reports)
print_file_report();
print_file_report(ctx);
return 0;
}
infd=0;
ctx->infd=0;
mprint ("\n\r-----------------------------------------------------------------\n");
mprint ("\rReading from standard input\n");
return 1;
}
if (ccx_options.input_source==CCX_DS_NETWORK)
{
if (infd!=-1) // Means we have already bound a socket.
if (ctx->infd!=-1) // Means we have already bound a socket.
{
if (ccx_options.print_file_reports)
print_file_report();
print_file_report(ctx);
return 0;
}
if (init_sockets())
return 1;
infd=socket(AF_INET,SOCK_DGRAM,0);
if (IN_MULTICAST(ccx_options.udpaddr))
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
return 1;
if(ctx->infd < 0)
fatal (CCX_COMMON_EXIT_BUG_BUG, "socket() failed.");
}
if (ccx_options.input_source==CCX_DS_TCP)
{
if (ctx->infd != -1)
{
int on = 1;
(void)setsockopt(infd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
}
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(IN_MULTICAST(ccx_options.udpaddr) ? ccx_options.udpaddr : INADDR_ANY);
servaddr.sin_port=htons(ccx_options.udpport);
if (bind(infd,(struct sockaddr *)&servaddr,sizeof(servaddr)))
{
fatal (EXIT_BUG_BUG, "bind() failed.");
}
if (IN_MULTICAST(ccx_options.udpaddr)) {
struct ip_mreq group;
group.imr_multiaddr.s_addr = htonl(ccx_options.udpaddr);
group.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(infd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
fatal (EXIT_BUG_BUG, "cannot join multicast group.");
}
if (ccx_options.print_file_reports)
print_file_report(ctx);
return 0;
}
mprint ("\n\r-----------------------------------------------------------------\n");
if (ccx_options.udpaddr == INADDR_ANY)
{
mprint ("\rReading from UDP socket %u\n",ccx_options.udpport);
}
else
{
struct in_addr in;
in.s_addr = htonl(ccx_options.udpaddr);
mprint ("\rReading from UDP socket %s:%u\n", inet_ntoa(in), ccx_options.udpport);
}
ctx->infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
return 1;
}
/* Close current and make sure things are still sane */
if (infd!=-1)
if (ctx->infd!=-1)
{
if (ccx_options.print_file_reports)
print_file_report();
close_input_file ();
if (inputsize>0 && ((past+bytesinbuffer) < inputsize) && !processed_enough)
print_file_report(ctx);
close_input_file (ctx);
if (ctx->inputsize>0 && ((ctx->past+bytesinbuffer) < ctx->inputsize) && !dec_ctx->processed_enough)
{
mprint("\n\n\n\nATTENTION!!!!!!\n");
mprint("In switch_to_next_file(): Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
inputfile[current_file], current_file, past, inputsize);
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->past, ctx->inputsize);
}
if (ccx_options.binary_concat)
{
total_past+=inputsize;
past=0; // Reset always or at the end we'll have double the size
ctx->total_past+=ctx->inputsize;
ctx->past=0; // Reset always or at the end we'll have double the size
}
}
for (;;)
{
current_file++;
if (current_file>=num_input_files)
{
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", inputfile[current_file]);
mprint ("\rOpening file: %s\n", ctx->inputfile[ctx->current_file]);
#ifdef _WIN32
infd=OPEN (inputfile[current_file],O_RDONLY | O_BINARY);
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY | O_BINARY);
#else
infd=OPEN (inputfile[current_file],O_RDONLY);
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY);
#endif
if (infd == -1)
mprint ("\rWarning: Unable to open input file [%s]\n", inputfile[current_file]);
if (ctx->infd == -1)
mprint ("\rWarning: Unable to open input file [%s]\n", ctx->inputfile[ctx->current_file]);
else
{
activity_input_file_open (inputfile[current_file]);
activity_input_file_open (ctx->inputfile[ctx->current_file]);
if (!ccx_options.live_stream)
{
inputsize = getfilesize (infd);
ctx->inputsize = getfilesize (ctx->infd);
if (!ccx_options.binary_concat)
total_inputsize=inputsize;
ctx->total_inputsize=ctx->inputsize;
}
return 1; // Succeeded
}
}
return 0;
return 0;
}
void position_sanity_check ()
void position_sanity_check (void)
{
#ifdef SANITY_CHECK
if (in!=-1)
{
LLONG realpos=LSEEK (in,0,SEEK_CUR);
if (realpos!=past-filebuffer_pos+bytesinbuffer)
if (realpos!=ctx->past-filebuffer_pos+bytesinbuffer)
{
fatal (EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,past);
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,ctx->past);
}
}
}
#endif
}
@@ -250,20 +234,20 @@ void position_sanity_check ()
int init_file_buffer(void)
{
filebuffer_start=0;
filebuffer_pos=0;
filebuffer_pos=0;
if (filebuffer==NULL)
{
filebuffer=(unsigned char *) malloc (FILEBUFFERSIZE);
bytesinbuffer=0;
}
if (filebuffer==NULL)
if (filebuffer==NULL)
{
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
}
return 0;
}
void buffered_seek (int offset)
void buffered_seek (struct lib_ccx_ctx *ctx, int offset)
{
position_sanity_check();
if (offset<0)
@@ -272,17 +256,17 @@ void buffered_seek (int offset)
if (filebuffer_pos<0)
{
// We got into the start buffer (hopefully)
if (startbytes_pos+filebuffer_pos < 0)
if ((filebuffer_pos+ctx->startbytes_pos) < 0)
{
fatal (EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
fatal (CCX_COMMON_EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
}
startbytes_pos+=filebuffer_pos;
ctx->startbytes_pos+=filebuffer_pos;
filebuffer_pos=0;
}
}
else
{
buffered_read_opt (NULL, offset);
buffered_read_opt (ctx, NULL, offset);
position_sanity_check();
}
}
@@ -291,7 +275,7 @@ void sleepandchecktimeout (time_t start)
{
if (ccx_options.input_source==CCX_DS_STDIN)
{
// CFS: Not 100% sure about this. Fine for files, not so sure what happens if stdin is
// 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;
@@ -304,7 +288,7 @@ void sleepandchecktimeout (time_t start)
return;
}
if (time(NULL)>start+ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
ccx_options.live_stream=0;
ccx_options.live_stream=0;
else
sleep_secs(1);
}
@@ -313,7 +297,7 @@ void return_to_buffer (unsigned char *buffer, unsigned int bytes)
{
if (bytes == filebuffer_pos)
{
// Usually we're just going back in the buffer and memcpy would be
// 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);
@@ -326,44 +310,44 @@ void return_to_buffer (unsigned char *buffer, unsigned int bytes)
// we're never here in ccextractor.
memmove (filebuffer,filebuffer+filebuffer_pos,bytesinbuffer-filebuffer_pos);
bytesinbuffer-=filebuffer_pos;
bytesinbuffer=0;
bytesinbuffer=0;
filebuffer_pos=0;
}
if (bytesinbuffer + bytes > FILEBUFFERSIZE)
fatal (EXIT_BUG_BUG, "Invalid return_to_buffer() - please submit a bug report.");
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;
}
LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes)
{
LLONG copied=0;
position_sanity_check();
time_t seconds=0;
if (ccx_options.live_stream>0)
time (&seconds);
if (ccx_options.live_stream>0)
time (&seconds);
if (ccx_options.buffer_input || filebuffer_pos<bytesinbuffer)
{
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
int eof = (infd==-1);
{
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
int eof = (ctx->infd==-1);
while ((!eof || ccx_options.live_stream) && bytes)
{
{
if (eof)
{
// No more data available inmediately, we sleep a while to give time
// for the data to come up
// for the data to come up
sleepandchecktimeout (seconds);
}
size_t ready = bytesinbuffer-filebuffer_pos;
size_t ready = bytesinbuffer-filebuffer_pos;
if (ready==0) // We really need to read more
{
if (!ccx_options.buffer_input)
{
// We got in the buffering code because of the initial buffer for
// detection stuff. However we don't want more buffering so
// detection stuff. However we don't want more buffering so
// we do the rest directly on the final buffer.
int i;
do
@@ -372,7 +356,7 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
// buffered - if here, then it must be files.
if (buffer!=NULL) // Read
{
i=read (infd,buffer,bytes);
i=read (ctx->infd,buffer,bytes);
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
buffer+=i;
@@ -380,10 +364,10 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
else // Seek
{
LLONG op, np;
op =LSEEK (infd,0,SEEK_CUR); // Get current pos
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 (infd,bytes,SEEK_CUR); // Pos after moving
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
i=(int) (np-op);
}
if (i==0 && ccx_options.live_stream)
@@ -403,31 +387,28 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
copied+=i;
bytes-=i;
}
}
while ((i || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(copied))) && bytes);
return copied;
while ((i || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))) && bytes);
return copied;
}
// Keep the last 8 bytes, so we have a guaranteed
// Keep the last 8 bytes, so we have a guaranteed
// working seek (-8) - needed by mythtv.
int keep = bytesinbuffer > 8 ? 8 : bytesinbuffer;
memmove (filebuffer,filebuffer+(FILEBUFFERSIZE-keep),keep);
int i;
if (ccx_options.input_source==CCX_DS_FILE || ccx_options.input_source==CCX_DS_STDIN)
i=read (infd, filebuffer+keep,FILEBUFFERSIZE-keep);
i=read (ctx->infd, filebuffer+keep,FILEBUFFERSIZE-keep);
else
{
socklen_t len = sizeof(cliaddr);
i = recvfrom(infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,(struct sockaddr *)&cliaddr,&len);
}
if( i == -1)
i = recvfrom(ctx->infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,NULL,NULL);
if (i == -1)
fatal (EXIT_READ_ERROR, "Error reading input stream!\n");
if (i==0)
{
/* If live stream, don't try to switch - acknowledge eof here as it won't
cause a loop end */
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(copied)))
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx, copied)))
eof=1;
}
filebuffer_pos=keep;
@@ -437,27 +418,27 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
int copy = (int) (ready>=bytes ? bytes:ready);
if (copy)
{
if (buffer!=NULL)
if (buffer!=NULL)
{
memcpy (buffer, filebuffer+filebuffer_pos, copy);
memcpy (buffer, filebuffer+filebuffer_pos, copy);
buffer+=copy;
}
filebuffer_pos+=copy;
filebuffer_pos+=copy;
bytes-=copy;
copied+=copy;
}
}
return copied;
}
else // Read without buffering
else // Read without buffering
{
if (buffer!=NULL)
{
int i;
while (bytes>0 && infd!=-1 &&
((i=read(infd,buffer,bytes))!=0 || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(copied))))
while (bytes>0 && ctx->infd!=-1 &&
((i=read(ctx->infd,buffer,bytes))!=0 || ccx_options.live_stream ||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))))
{
if( i == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
@@ -474,13 +455,13 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
}
// return fread(buffer,1,bytes,in);
//return FSEEK (in,bytes,SEEK_CUR);
while (bytes!=0 && infd!=-1)
while (bytes!=0 && ctx->infd!=-1)
{
LLONG op, np;
op =LSEEK (infd,0,SEEK_CUR); // Get current pos
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 (infd,bytes,SEEK_CUR); // Pos after moving
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
copied=copied+(np-op);
bytes=bytes-(unsigned int) copied;
if (copied==0)
@@ -490,7 +471,7 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
else
{
if (ccx_options.binary_concat)
switch_to_next_file(0);
switch_to_next_file(ctx, 0);
else
break;
}

View File

@@ -1,13 +1,13 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include "708.h"
#include "dvb_subtitle_decoder.h"
#include "ccx_encoders_common.h"
// IMPORTED TRASH INFO, REMOVE
extern long num_nal_unit_type_7;
extern long num_vcl_hrd;
@@ -20,20 +20,15 @@ extern long num_unexpected_sei_length;
unsigned current_vert_size = 0;
unsigned current_aspect_ratio = 0;
unsigned current_frame_rate = 4; // Assume standard fps, 29.97
double current_fps = (double) 30000.0 / 1001; /* 29.97 */ // TODO: Get from framerates_values[] instead
LLONG current_pts = 0;
unsigned rollover_bits = 0; // The PTS rolls over every 26 hours and that can happen in the middle of a stream.
LLONG result; // Number of bytes read/skipped in last read operation
int end_of_file=0; // End of file?
const static unsigned char DO_NOTHING[] = {0x80, 0x80};
LLONG inbuf = 0; // Number of bytes loaded in buffer
LLONG inbuf = 0; // Number of bytes loaded in buffer
int ccx_bufferdatatype = CCX_PES; // Can be RAW, PES, H264 or Hauppage
int current_tref = 0; // Store temporal reference of current frame
enum ccx_frame_type current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
// Remember if the last header was valid. Used to suppress too much output
// and the expected unrecognized first header for TiVo files.
int strangeheader=0;
@@ -42,12 +37,10 @@ unsigned char *filebuffer;
LLONG filebuffer_start; // Position of buffer start relative to file
int filebuffer_pos; // Position of pointer relative to buffer start
int bytesinbuffer; // Number of bytes we actually have on buffer
extern void *cxx_dvb_context;
LLONG process_raw_with_field (void);
extern void *ccx_dvb_context;
// Program stream specific data grabber
LLONG ps_getmoredata(void)
LLONG ps_getmoredata(struct lib_ccx_ctx *ctx)
{
int enough = 0;
int payload_read = 0;
@@ -58,18 +51,18 @@ LLONG ps_getmoredata(void)
int falsepack=0;
// Read and return the next video PES payload
do
do
{
if (BUFSIZE-inbuf<500)
if (BUFSIZE-inbuf<500)
{
mprint("Less than 500 left\n");
enough=1; // Stop when less than 500 bytes are left in buffer
}
else
else
{
buffered_read(nextheader,6);
past+=result;
if (result!=6)
buffered_read(ctx, nextheader, 6);
ctx->past+=result;
if (result!=6)
{
// Consider this the end of the show.
end_of_file=1;
@@ -78,7 +71,7 @@ LLONG ps_getmoredata(void)
// Search for a header that is not a picture header (nextheader[3]!=0x00)
while ( !(nextheader[0]==0x00 && nextheader[1]==0x00
&& nextheader[2]==0x01 && nextheader[3]!=0x00) )
&& nextheader[2]==0x01 && nextheader[3]!=0x00) )
{
if( !strangeheader )
{
@@ -99,10 +92,10 @@ LLONG ps_getmoredata(void)
{
int atpos = newheader-nextheader;
memmove (nextheader,newheader,(size_t)(hlen-atpos));
buffered_read(nextheader+(hlen-atpos),atpos);
past+=result;
if (result!=atpos)
memmove (nextheader,newheader,(size_t)(hlen-atpos));
buffered_read(ctx, nextheader+(hlen-atpos),atpos);
ctx->past+=result;
if (result!=atpos)
{
end_of_file=1;
break;
@@ -110,9 +103,9 @@ LLONG ps_getmoredata(void)
}
else
{
buffered_read(nextheader,hlen);
past+=result;
if (result!=hlen)
buffered_read(ctx, nextheader, hlen);
ctx->past+=result;
if (result!=hlen)
{
end_of_file=1;
break;
@@ -128,12 +121,12 @@ LLONG ps_getmoredata(void)
strangeheader=0;
// PACK header
if ( nextheader[3]==0xBA)
if ( nextheader[3]==0xBA)
{
dbg_print(CCX_DMT_VERBOSE, "PACK header\n");
buffered_read(nextheader+6,8);
past+=result;
if (result!=8)
buffered_read(ctx, nextheader+6,8);
ctx->past+=result;
if (result!=8)
{
// Consider this the end of the show.
end_of_file=1;
@@ -142,7 +135,7 @@ LLONG ps_getmoredata(void)
if ( (nextheader[4]&0xC4)!=0x44 || !(nextheader[6]&0x04)
|| !(nextheader[8]&0x04) || !(nextheader[9]&0x01)
|| (nextheader[12]&0x03)!=0x03 )
|| (nextheader[12]&0x03)!=0x03 )
{
// broken pack header
falsepack=1;
@@ -150,20 +143,20 @@ LLONG ps_getmoredata(void)
// We don't need SCR/SCR_ext
int stufflen=nextheader[13]&0x07;
if (falsepack)
if (falsepack)
{
mprint ("Warning: Defective Pack header\n");
}
// If not defect, load stuffing
buffered_skip ((int) stufflen);
past+=stufflen;
buffered_skip (ctx, (int) stufflen);
ctx->past+=stufflen;
// fake a result value as something was skipped
result=1;
continue;
}
// Some PES stream
else if (nextheader[3]>=0xBB && nextheader[3]<=0xDF)
else if (nextheader[3]>=0xBB && nextheader[3]<=0xDF)
{
// System header
// nextheader[3]==0xBB
@@ -188,18 +181,18 @@ LLONG ps_getmoredata(void)
}
// Skip over it
buffered_skip ((int) headerlen);
past+=headerlen;
buffered_skip (ctx, (int) headerlen);
ctx->past+=headerlen;
// fake a result value as something was skipped
result=1;
continue;
}
// Read the next video PES
else if ((nextheader[3]&0xf0)==0xe0)
else if ((nextheader[3]&0xf0)==0xe0)
{
int hlen; // Dummy variable, unused
int peslen = read_video_pes_header(nextheader, &hlen, 0);
int peslen = read_video_pes_header(ctx, nextheader, &hlen, 0);
if (peslen < 0)
{
end_of_file=1;
@@ -220,8 +213,8 @@ LLONG ps_getmoredata(void)
continue;
}
buffered_read (buffer+inbuf,want);
past=past+result;
buffered_read (ctx, ctx->buffer+inbuf, want);
ctx->past=ctx->past+result;
if (result>0) {
payload_read+=(int) result;
}
@@ -239,7 +232,7 @@ LLONG ps_getmoredata(void)
strangeheader=1;
}
}
}
}
while (result!=0 && !enough && BUFSIZE!=inbuf);
dbg_print(CCX_DMT_VERBOSE, "PES data read: %d\n", payload_read);
@@ -249,30 +242,31 @@ LLONG ps_getmoredata(void)
// Returns number of bytes read, or zero for EOF
LLONG general_getmoredata(void)
LLONG general_getmoredata(struct lib_ccx_ctx *ctx)
{
int bytesread = 0;
int want;
do
{
do
{
want = (int) (BUFSIZE-inbuf);
buffered_read (buffer+inbuf,want); // This is a macro.
buffered_read (ctx, ctx->buffer+inbuf,want); // This is a macro.
// 'result' HAS the number of bytes read
past=past+result;
ctx->past=ctx->past+result;
inbuf+=result;
bytesread+=(int) result;
} while (result!=0 && result!=want);
return bytesread;
}
#ifdef WTV_DEBUG
// Hexadecimal dump process
void processhex (char *filename)
void processhex (struct lib_ccx_ctx *ctx, char *filename)
{
size_t max=(size_t) inputsize+1; // Enough for the whole thing. Hex dumps are small so we can be lazy here
size_t max=(size_t) ctx->inputsize+1; // Enough for the whole thing. Hex dumps are small so we can be lazy here
char *line=(char *) malloc (max);
/* const char *mpeg_header="00 00 01 b2 43 43 01 f8 "; // Always present */
FILE *fr = fopen (filename, "rt");
FILE *fr = fopen (filename, "rt");
unsigned char *bytes=NULL;
unsigned byte_count=0;
int warning_shown=0;
@@ -280,7 +274,7 @@ void processhex (char *filename)
{
char *c1, *c2=NULL; // Positions for first and second colons
/* int len; */
long timing;
long timing;
if (line[0]==';') // Skip comments
continue;
c1=strchr (line,':');
@@ -291,7 +285,7 @@ void processhex (char *filename)
*c2=0;
/* len=atoi (line); */
timing=atol (c1+2)*(MPEG_CLOCK_FREQ/1000);
current_pts=timing;
current_pts=timing;
if (pts_set==0)
pts_set=1;
set_fts();
@@ -300,10 +294,10 @@ void processhex (char *filename)
if (strlen (c2)==8)
{
unsigned char high1=c2[1];
unsigned char low1=c2[2];
unsigned char low1=c2[2];
int value1=hex2int (high1,low1);
unsigned char high2=c2[4];
unsigned char low2=c2[5];
unsigned char low2=c2[5];
int value2=hex2int (high2,low2);
buffer[0]=value1;
buffer[1]=value2;
@@ -327,7 +321,7 @@ void processhex (char *filename)
// OK, seems like a decent chunk of CCdata.
c2+=strlen (mpeg_header);
*/
byte_count=strlen (c2)/3;
byte_count=strlen (c2)/3;
/*
if (atoi (line)!=byte_count+strlen (mpeg_header)/3) // Number of bytes reported don't match actual contents
continue;
@@ -336,42 +330,42 @@ void processhex (char *filename)
continue;
if (!byte_count) // Nothing to get from this line except timing info, already done.
continue;
bytes=(unsigned char *) malloc (byte_count);
bytes=(unsigned char *) malloc (byte_count);
if (!bytes)
fatal (EXIT_NOT_ENOUGH_MEMORY, "Out of memory.\n");
unsigned char *bytes=(unsigned char *) malloc (byte_count);
for (unsigned i=0;i<byte_count;i++)
{
unsigned char high=c2[0];
unsigned char low=c2[1];
unsigned char low=c2[1];
int value=hex2int (high,low);
if (value==-1)
fatal (EXIT_FAILURE, "Incorrect format, unexpected non-hex string.");
bytes[i]=value;
c2+=3;
}
memcpy (buffer, bytes, byte_count);
memcpy (ctx->buffer, bytes, byte_count);
inbuf=byte_count;
process_raw();
continue;
// New wtv format, everything else hopefully obsolete
int ok=0; // Were we able to process the line?
// Attempt to detect how the data is encoded.
// Attempt to detect how the data is encoded.
// Case 1 (seen in all elderman's samples):
// 18 : 467 : 00 00 01 b2 43 43 01 f8 03 42 ff fd 54 80 fc 94 2c ff
// Always 03 after header, then something unknown (seen 42, 43, c2, c3...),
// 18 : 467 : 00 00 01 b2 43 43 01 f8 03 42 ff fd 54 80 fc 94 2c ff
// Always 03 after header, then something unknown (seen 42, 43, c2, c3...),
// then ff, then data with field info, and terminated with ff.
if (byte_count>3 && bytes[0]==0x03 &&
bytes[2]==0xff && bytes[byte_count-1]==0xff)
{
{
ok=1;
for (unsigned i=3; i<byte_count-2; i+=3)
{
inbuf=3;
buffer[0]=bytes[i];
buffer[1]=bytes[i+1];
buffer[2]=bytes[i+2];
ctx->buffer[0]=bytes[i];
ctx->buffer[1]=bytes[i+1];
ctx->buffer[2]=bytes[i+2];
process_raw_with_field();
}
}
@@ -383,18 +377,18 @@ void processhex (char *filename)
/* unsigned extra_field_flag=magic&1; */
unsigned caption_count=((magic>>1)&0x1F);
unsigned filler=((magic>>6)&1);
/* unsigned pattern=((magic>>7)&1); */
/* unsigned pattern=((magic>>7)&1); */
int always_ff=1;
int current_field=0;
int current_field=0;
if (filler==0 && caption_count*6==byte_count-1) // Note that we are ignoring the extra field for now...
{
ok=1;
ok=1;
for (unsigned i=1; i<byte_count-2; i+=3)
if (bytes[i]!=0xff)
{
// If we only find FF in the first byte then either there's only field 1 data, OR
// there's alternating field 1 and field 2 data. Don't know how to tell apart. For now
// let's assume that always FF means alternating.
// let's assume that always FF means alternating.
always_ff=0;
break;
}
@@ -404,14 +398,14 @@ void processhex (char *filename)
inbuf=3;
if (always_ff) // Try to tell apart the fields based on the pattern field.
{
buffer[0]=current_field | 4; // | 4 to enable the 'valid' bit
current_field = !current_field;
ctx->buffer[0]=current_field | 4; // | 4 to enable the 'valid' bit
current_field = !current_field;
}
else
buffer[0]=bytes[i];
ctx->buffer[0]=bytes[i];
buffer[1]=bytes[i+1];
buffer[2]=bytes[i+2];
ctx->buffer[1]=bytes[i+1];
ctx->buffer[2]=bytes[i+2];
process_raw_with_field();
}
}
@@ -423,18 +417,20 @@ void processhex (char *filename)
}
free (bytes);
}
fclose(fr);
fclose(fr);
}
#endif
// Raw file process
void raw_loop ()
void raw_loop (struct lib_ccx_ctx *ctx, void *enc_ctx)
{
LLONG got;
LLONG processed;
struct cc_subtitle dec_sub;
current_pts = 90; // Pick a valid PTS time
pts_set = 1;
set_fts(); // Now set the FTS related variables
memset(&dec_sub, 0, sizeof(dec_sub));
dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)",
print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
(unsigned) (current_pts));
@@ -444,12 +440,17 @@ void raw_loop ()
{
inbuf=0;
got=general_getmoredata();
got = general_getmoredata(ctx);
if (got == 0) // Shortcircuit if we got nothing to process
break;
processed=process_raw();
processed=process_raw(ctx, &dec_sub);
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
dec_sub.got_output = 0;
}
int ccblocks = cb_field1;
current_pts += cb_field1*1001/30*(MPEG_CLOCK_FREQ/1000);
@@ -460,10 +461,10 @@ void raw_loop ()
(unsigned) (current_pts));
dbg_print(CCX_DMT_VIDES, " FTS: %s incl. %d CB\n",
print_mstime(get_fts()), ccblocks);
if (processed<got)
{
mprint ("BUG BUG\n");
mprint ("BUG BUG\n");
}
}
while (inbuf);
@@ -471,78 +472,87 @@ void raw_loop ()
/* Process inbuf bytes in buffer holding raw caption data (three byte packets, the first being the field).
* The number of processed bytes is returned. */
LLONG process_raw_with_field (void)
LLONG process_raw_with_field (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
{
unsigned char data[3];
data[0]=0x04; // Field 1
current_field=1;
unsigned char data[3];
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
data[0]=0x04; // Field 1
current_field=1;
for (unsigned long i=0; i<inbuf; i=i+3)
{
if ( !saw_caption_block && *(buffer+i)==0xff && *(buffer+i+1)==0xff)
{
// Skip broadcast header
}
else
{
data[0]=buffer[i];
data[1]=buffer[i+1];
data[2]=buffer[i+2];
for (unsigned long i=0; i<inbuf; i=i+3)
{
if ( !dec_ctx->saw_caption_block && *(ctx->buffer+i)==0xff && *(ctx->buffer+i+1)==0xff)
{
// Skip broadcast header
}
else
{
data[0]=ctx->buffer[i];
data[1]=ctx->buffer[i+1];
data[2]=ctx->buffer[i+2];
// do_cb increases the cb_field1 counter so that get_fts()
// is correct.
do_cb(data);
}
}
return inbuf;
// do_cb increases the cb_field1 counter so that get_fts()
// is correct.
do_cb(dec_ctx, data, sub);
}
}
return inbuf;
}
/* Process inbuf bytes in buffer holding raw caption data (two byte packets).
* The number of processed bytes is returned. */
LLONG process_raw (void)
LLONG process_raw (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
{
unsigned char data[3];
unsigned char data[3];
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
data[0]=0x04; // Field 1
current_field=1;
for (unsigned long i=0; i<inbuf; i=i+2)
{
if ( !saw_caption_block && *(buffer+i)==0xff && *(buffer+i+1)==0xff)
if ( !dec_ctx->saw_caption_block && *(ctx->buffer+i)==0xff && *(ctx->buffer+i+1)==0xff)
{
// Skip broadcast header
// Skip broadcast header
}
else
{
data[1]=buffer[i];
data[2]=buffer[i+1];
data[1]=ctx->buffer[i];
data[2]=ctx->buffer[i+1];
// do_cb increases the cb_field1 counter so that get_fts()
// is correct.
do_cb(data);
do_cb(dec_ctx, data, sub);
}
}
return inbuf;
}
void general_loop(void)
void general_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
{
LLONG overlap=0;
LLONG pos = 0; /* Current position in buffer */
LLONG overlap=0;
LLONG pos = 0; /* Current position in buffer */
struct cc_subtitle dec_sub;
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
dec_ctx->wbout1 = (struct ccx_s_write*)&ctx->wbout1 ;
dec_ctx->wbout2 = (struct ccx_s_write*)&ctx->wbout2 ;
inbuf = 0; // No data yet
end_of_file = 0;
current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
while (!end_of_file && !processed_enough)
memset(&dec_sub, 0,sizeof(dec_sub));
while (!end_of_file && !dec_ctx->processed_enough)
{
/* Get rid of the bytes we already processed */
overlap=inbuf-pos;
/* Get rid of the bytes we already processed */
overlap=inbuf-pos;
if ( pos != 0 ) {
// Only when needed as memmove has been seen crashing
// for dest==source and n >0
memmove (buffer,buffer+pos,(size_t) (inbuf-pos));
memmove (ctx->buffer,ctx->buffer+pos,(size_t) (inbuf-pos));
inbuf-=pos;
}
pos = 0;
@@ -550,35 +560,35 @@ void general_loop(void)
// GET MORE DATA IN BUFFER
LLONG i;
position_sanity_check();
switch (stream_mode)
switch (ctx->stream_mode)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
i = general_getmoredata();
i = general_getmoredata(ctx);
break;
case CCX_SM_TRANSPORT:
i = ts_getmoredata();
i = ts_getmoredata(ctx);
break;
case CCX_SM_PROGRAM:
i = ps_getmoredata();
i = ps_getmoredata(ctx);
break;
case CCX_SM_ASF:
i = asf_getmoredata();
i = asf_getmoredata(ctx);
break;
case CCX_SM_WTV:
i = wtv_getmoredata();
i = wtv_getmoredata(ctx);
break;
default:
fatal(EXIT_BUG_BUG, "Impossible stream_mode");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible stream_mode");
}
position_sanity_check();
if (fh_out_elementarystream!=NULL)
fwrite (buffer+overlap,1,(size_t) (inbuf-overlap),fh_out_elementarystream);
if (ctx->fh_out_elementarystream!=NULL)
fwrite (ctx->buffer+overlap,1,(size_t) (inbuf-overlap),ctx->fh_out_elementarystream);
if (i==0)
{
end_of_file = 1;
memset (buffer+inbuf, 0, (size_t) (BUFSIZE-inbuf)); /* Clear buffer at the end */
memset (ctx->buffer+inbuf, 0, (size_t) (BUFSIZE-inbuf)); /* Clear buffer at the end */
}
if (inbuf == 0)
@@ -593,26 +603,25 @@ void general_loop(void)
if (ccx_options.hauppauge_mode)
{
got = process_raw_with_field();
got = process_raw_with_field(ctx, &dec_sub);
if (pts_set)
set_fts(); // Try to fix timing from TS data
}
else if(ccx_bufferdatatype == CCX_DVB_SUBTITLE)
{
int out_size = 0;
dvbsub_decode(cxx_dvb_context,NULL,&out_size,buffer + 2,inbuf);
dvbsub_decode(ccx_dvb_context, ctx->buffer + 2, inbuf, &dec_sub);
set_fts();
got = inbuf;
}
else if (ccx_bufferdatatype == CCX_PES)
{
got = process_m2v (buffer, inbuf);
}
else if (ccx_bufferdatatype == CCX_PES)
{
got = process_m2v (ctx, ctx->buffer, inbuf,&dec_sub);
}
else if (ccx_bufferdatatype == CCX_TELETEXT)
{
// Dispatch to Petr Kutalek 's telxcc.
tlt_process_pes_packet (buffer, (uint16_t) inbuf);
got = inbuf;
tlt_process_pes_packet (ctx, ctx->buffer, (uint16_t) inbuf);
got = inbuf;
}
else if (ccx_bufferdatatype == CCX_PRIVATE_MPEG2_CC)
{
@@ -654,18 +663,18 @@ void general_loop(void)
(unsigned) (current_pts));
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
got = process_raw();
got = process_raw(ctx, &dec_sub);
}
else if (ccx_bufferdatatype == CCX_H264) // H.264 data from TS file
{
got = process_avc(buffer, inbuf);
got = process_avc(ctx, ctx->buffer, inbuf,&dec_sub);
}
else
fatal(EXIT_BUG_BUG, "Unknown data type!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Unknown data type!");
if (got>inbuf)
{
mprint ("BUG BUG\n");
mprint ("BUG BUG\n");
}
pos+=got;
@@ -673,39 +682,44 @@ void general_loop(void)
{
int cur_sec = (int) (get_fts() / 1000);
int th=cur_sec/10;
if (last_reported_progress!=th)
if (ctx->last_reported_progress!=th)
{
activity_progress (-1,cur_sec/60, cur_sec%60);
last_reported_progress = th;
ctx->last_reported_progress = th;
}
}
else
{
if (total_inputsize>255) // Less than 255 leads to division by zero below.
if (ctx->total_inputsize>255) // Less than 255 leads to division by zero below.
{
int progress = (int) ((((total_past+past)>>8)*100)/(total_inputsize>>8));
if (last_reported_progress != progress)
int progress = (int) ((((ctx->total_past+ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
if (ctx->last_reported_progress != progress)
{
LLONG t=get_fts();
if (!t && global_timestamp_inited)
t=global_timestamp-min_global_timestamp;
if (!t && ctx->global_timestamp_inited)
t=ctx->global_timestamp-ctx->min_global_timestamp;
int cur_sec = (int) (t / 1000);
activity_progress(progress, cur_sec/60, cur_sec%60);
last_reported_progress = progress;
activity_progress(progress, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = progress;
}
}
}
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
dec_sub.got_output = 0;
}
position_sanity_check();
}
// Flush remaining HD captions
if (has_ccdata_buffered)
process_hdcc();
process_hdcc(ctx, &dec_sub);
if (total_past!=total_inputsize && ccx_options.binary_concat && !processed_enough)
if (ctx->total_past!=ctx->total_inputsize && ccx_options.binary_concat && !dec_ctx->processed_enough)
{
mprint("\n\n\n\nATTENTION!!!!!!\n");
mprint("Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
inputfile[current_file], current_file, past, inputsize);
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->past, ctx->inputsize);
}
mprint ("\nNumber of NAL_type_7: %ld\n",num_nal_unit_type_7);
mprint ("Number of VCL_HRD: %ld\n",num_vcl_hrd);
@@ -715,26 +729,30 @@ void general_loop(void)
}
// Raw caption with FTS file process
void rcwt_loop( void )
void rcwt_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
{
static unsigned char *parsebuf;
static long parsebufsize = 1024;
struct cc_subtitle dec_sub;
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
memset(&dec_sub, 0,sizeof(dec_sub));
// As BUFSIZE is a macro this is just a reminder
if (BUFSIZE < (3*0xFFFF + 10))
fatal (EXIT_BUG_BUG, "BUFSIZE too small for RCWT caption block.\n");
fatal (CCX_COMMON_EXIT_BUG_BUG, "BUFSIZE too small for RCWT caption block.\n");
// Generic buffer to hold some data
parsebuf = (unsigned char*)malloc(1024);
LLONG currfts;
uint16_t cbcount = 0;
int bread = 0; // Bytes read
buffered_read(parsebuf,11);
past+=result;
buffered_read(ctx, parsebuf, 11);
ctx->past+=result;
bread+=(int) result;
if (result!=11)
{
@@ -750,13 +768,19 @@ void rcwt_loop( void )
dbg_print(CCX_DMT_PARSE, "File created by %02X version %02X%02X\nFile format revision: %02X%02X\n",
parsebuf[3], parsebuf[4], parsebuf[5],
parsebuf[6], parsebuf[7]);
}
else
{
fatal(EXIT_MISSING_RCWT_HEADER, "Missing RCWT header. Abort.\n");
}
if (parsebuf[6] == 0 && parsebuf[7] == 2)
{
tlt_read_rcwt(ctx);
return;
}
// Initialize first time. As RCWT files come with the correct FTS the
// initial (minimal) time needs to be set to 0.
current_pts = 0;
@@ -767,8 +791,8 @@ void rcwt_loop( void )
while(1)
{
// Read the data header
buffered_read(parsebuf,10);
past+=result;
buffered_read(ctx, parsebuf, 10);
ctx->past+=result;
bread+=(int) result;
if (result!=10)
@@ -794,8 +818,8 @@ void rcwt_loop( void )
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
parsebufsize = cbcount*3;
}
buffered_read(parsebuf,cbcount*3);
past+=result;
buffered_read(ctx, parsebuf, cbcount*3);
ctx->past+=result;
bread+=(int) result;
if (result!=cbcount*3)
{
@@ -817,9 +841,14 @@ void rcwt_loop( void )
for (int j=0; j<cbcount*3; j=j+3)
{
do_cb(parsebuf+j);
do_cb(dec_ctx, parsebuf+j, &dec_sub);
}
}
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
dec_sub.got_output = 0;
}
} // end while(1)
dbg_print(CCX_DMT_PARSE, "Processed %d bytes\n", bread);

128
src/lib_ccx/lib_ccx.c Normal file
View File

@@ -0,0 +1,128 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
struct ccx_common_logging_t ccx_common_logging;
static struct ccx_decoders_common_settings_t *init_decoder_setting(
struct ccx_s_options *opt)
{
struct ccx_decoders_common_settings_t *setting;
setting = malloc(sizeof(struct ccx_decoders_common_settings_t));
if(!setting)
return NULL;
setting->subs_delay = opt->subs_delay;
setting->output_format = opt->write_format;
setting->fix_padding = opt->fix_padding;
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;
return setting;
}
static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setting)
{
freep(setting);
}
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
{
struct lib_ccx_ctx *ctx;
struct ccx_decoder_608_report *report_608;
struct ccx_decoders_common_settings_t *dec_setting;
ctx = malloc(sizeof(struct lib_ccx_ctx));
if(!ctx)
return NULL;
memset(ctx,0,sizeof(struct lib_ccx_ctx));
report_608 = malloc(sizeof(struct ccx_decoder_608_report));
if (!report_608)
return NULL;
memset(report_608,0,sizeof(struct ccx_decoder_608_report));
ctx->capbufsize = 20000;
ctx->capbuf = NULL;
ctx->capbuflen = 0; // Bytes read in capbuf
// Initialize some constants
init_ts(ctx);
init_avc();
ctx->stream_mode = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
ctx->auto_stream = opt->auto_stream;
ctx->m2ts = opt->m2ts;
ctx->screens_to_process = -1;
ctx->current_file = -1;
ctx->infd = -1;//Set to -1 to indicate no file is open.
// Default name for output files if input is stdin
ctx->basefilename_for_stdin=(char *) "stdin";
// Default name for output files if input is network
ctx->basefilename_for_network=(char *) "network";
// Set logging functions for libraries
ccx_common_logging.debug_ftn = &dbg_print;
ccx_common_logging.debug_mask = opt->debug_mask;
ccx_common_logging.fatal_ftn = &fatal;
ccx_common_logging.log_ftn = &mprint;
ccx_common_logging.gui_ftn = &activity_library_process;
// Need to set the 608 data for the report to the correct variable.
ctx->freport.data_from_608 = report_608;
// Same applies for 708 data
ctx->freport.data_from_708 = &ccx_decoder_708_report;
// Init shared decoder settings
dec_setting = init_decoder_setting(opt);
ctx->dec_ctx = init_cc_decode(dec_setting);
dinit_decoder_setting(&dec_setting);
// Init encoder helper variables
ccx_encoders_helpers_setup(opt->encoding, opt->nofontcolor, opt->notypesetting, opt->trim_subs);
// Init 708 decoder(s)
ccx_decoders_708_init_library(ctx->basefilename,ctx->extension,opt->print_file_reports);
// Set output structures for the 608 decoder
//ctx->dec_ctx->context_cc608_field_1->out = ctx->dec_ctx->wbout1;
//ctx->dec_ctx->context_cc608_field_2->out = ctx->dec_ctx->wbout2;
// Init XDS buffers
ccx_decoders_xds_init_library(&opt->transcript_settings, ctx->subs_delay, opt->millis_separator);
//xds_cea608_test();
//Initialize input files
ctx->inputfile = opt->inputfile;
ctx->num_input_files = opt->num_input_files;
ctx->subs_delay = opt->subs_delay;
ctx->wbout1.filename = opt->wbout2.filename;
ctx->wbout2.filename = opt->wbout2.filename;
ctx->buffer = (unsigned char *) malloc (BUFSIZE);
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
// Init timing
ccx_common_timing_init(&ctx->past,opt->nosync);
ctx->cc_to_stdout = opt->cc_to_stdout;
build_parity_table();
return ctx;
}
void dinit_libraries( struct lib_ccx_ctx **ctx)
{
struct lib_ccx_ctx *lctx = *ctx;
int i = 0;
for (i = 0; i < MAX_PID; i++)
{
if( lctx->PIDs_programs[i])
freep(lctx->PIDs_programs + i);
}
// 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(ctx);
}

476
src/lib_ccx/lib_ccx.h Normal file
View File

@@ -0,0 +1,476 @@
#ifndef CCX_CCEXTRACTOR_H
#define CCX_CCEXTRACTOR_H
#define VERSION "0.76"
// Load common includes and constants for library usage
#include "ccx_common_platform.h"
#include "ccx_common_constants.h"
#include "ccx_common_common.h"
#include "ccx_common_char_encoding.h"
#include "ccx_common_structs.h"
#include "ccx_common_timing.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "ccx_decoders_608.h"
#include "ccx_decoders_xds.h"
#include "ccx_decoders_708.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];
};
/* Report information */
#define SUB_STREAMS_CNT 10
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];
unsigned mp4_cc_track_cnt;
};
// Stuff for telcc.c
struct ccx_s_teletext_config {
uint8_t verbose : 1; // should telxcc be verbose?
uint16_t page; // teletext page containing cc we want to filter
uint16_t tid; // 13-bit packet ID for teletext stream
double offset; // time offset in seconds
uint8_t bom : 1; // print UTF-8 BOM characters at the beginning of output
uint8_t nonempty : 1; // produce at least one (dummy) frame
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
// uint64_t utc_refvalue; // UTC referential value => Moved to 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
};
#define MAX_PID 65536
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;
LLONG total_past; // Only in binary concat mode
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;
int stat_dvdccheaders;
int stat_scte20ccheaders;
int stat_replay5000headers;
int stat_replay4000headers;
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;
int rawmode; // Broadcast or DVD
// See -d from
int cc_to_stdout; // If 1, captions go to stdout instead of file
LLONG subs_delay; // ms to delay (or advance) subs
int startcredits_displayed;
int end_credits_displayed;
LLONG last_displayed_subs_ms; // When did the last subs end?
LLONG screens_to_process; // How many screenfuls we want?
char *basefilename; // Input filename without the extension
const char *extension; // Output extension
int current_file; // If current_file!=1, we are processing *inputfile[current_file]
char **inputfile; // List of files to process
int num_input_files; // How many?
/* Hauppauge support */
unsigned hauppauge_warning_shown; // Did we detect a possible Hauppauge capture and told the user already?
unsigned teletext_warning_shown; // Did we detect a possible PAL (with teletext subs) and told the user already?
// Output structures
struct ccx_s_write wbout1;
struct ccx_s_write wbout2;
/* File handles */
FILE *fh_out_elementarystream;
int infd; // descriptor number to input.
char *basefilename_for_stdin;
char *basefilename_for_network;
int PIDs_seen[MAX_PID];
struct PMT_entry *PIDs_programs[MAX_PID];
//struct EIT_buffer eit_buffer;
struct EIT_buffer epg_buffers[0xfff+1];
struct 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];
int epg_last_output;
int epg_last_live_output;
struct file_report freport;
long capbufsize;
unsigned char *capbuf;
long capbuflen; // Bytes read in capbuf
};
#ifdef DEBUG_TELEXCC
int main_telxcc (int argc, char *argv[]);
#endif
#define buffered_skip(ctx, bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
filebuffer_pos+=bytes; \
result=bytes; \
} else result=buffered_read_opt (ctx, NULL,bytes);
#define buffered_read(ctx, buffer,bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
if (buffer!=NULL) memcpy (buffer,filebuffer+filebuffer_pos,bytes); \
filebuffer_pos+=bytes; \
result=bytes; \
} else { result=buffered_read_opt (ctx, buffer,bytes); if (ccx_options.gui_mode_reports && ccx_options.input_source==CCX_DS_NETWORK) {net_activity_gui++; if (!(net_activity_gui%1000))activity_report_data_read();}}
#define buffered_read_4(buffer) if (4<=bytesinbuffer-filebuffer_pos) { \
if (buffer) { buffer[0]=filebuffer[filebuffer_pos]; \
buffer[1]=filebuffer[filebuffer_pos+1]; \
buffer[2]=filebuffer[filebuffer_pos+2]; \
buffer[3]=filebuffer[filebuffer_pos+3]; \
filebuffer_pos+=4; \
result=4; } \
} else result=buffered_read_opt (buffer,4);
#define buffered_read_byte(ctx, buffer) if (bytesinbuffer-filebuffer_pos) { \
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
filebuffer_pos++; \
result=1; } \
} else result=buffered_read_opt (ctx, buffer,1);
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes);
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt);
void dinit_libraries( struct lib_ccx_ctx **ctx);
//params.c
void parse_parameters (struct ccx_s_options *opt, int argc, char *argv[]);
void usage (void);
int atoi_hex (char *s);
int stringztoms (const char *s, struct ccx_boundary_time *bt);
// general_loop.c
void position_sanity_check (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 processhex (char *filename);
void rcwt_loop(struct lib_ccx_ctx *ctx, void *enc_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);
// 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);
// es_functions.c
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG 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);
// bitstream.c - see bitstream.h
// file_functions.c
LLONG getfilesize (int in);
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);
// sequencing.c
void init_hdcc (void);
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number,
LLONG current_fts_now,struct cc_subtitle *sub);
void anchor_hdcc(int seq);
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
// mp4.c
int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx);
// params_dump.c
void params_dump(struct lib_ccx_ctx *ctx);
void print_file_report(struct lib_ccx_ctx *ctx);
// output.c
void init_write(struct ccx_s_write *wb, char *filename);
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
void writedata(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub);
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile);
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data);
// stream_functions.c
void detect_stream_type (struct lib_ccx_ctx *ctx);
int detect_myth( struct lib_ccx_ctx *ctx );
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen);
int read_pts_pes(unsigned char*header, int len);
// 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 parse_EPG_packet (struct lib_ccx_ctx *ctx);
void EPG_free();
// myth.c
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
// utility.c
void fatal(int exit_code, const char *fmt, ...);
void dvprint(const char *fmt, ...);
void mprint (const char *fmt, ...);
void sleep_secs (int secs);
void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, unsigned clear_high_bit);
bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) ;
int hex2int (char high, char low);
void timestamp_to_srttime(uint64_t timestamp, char *buffer);
void timestamp_to_smptetttime(uint64_t timestamp, char *buffer);
void millis_to_date (uint64_t timestamp, char *buffer) ;
int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len);
#ifndef _WIN32
void m_signal(int sig, void (*func)(int));
#endif
unsigned encode_line (unsigned char *buffer, unsigned char *text);
void buffered_seek (struct lib_ccx_ctx *ctx, int offset);
extern void build_parity_table(void);
void tlt_process_pes_packet(struct lib_ccx_ctx *ctx, uint8_t *buffer, uint16_t size);
void telxcc_init(struct lib_ccx_ctx *ctx);
void telxcc_close(struct lib_ccx_ctx *ctx);
void tlt_read_rcwt(struct lib_ccx_ctx *ctx);
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 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;
#endif

921
src/lib_ccx/myth.c Normal file
View File

@@ -0,0 +1,921 @@
/* This code comes from MythTV.
For now, integration with ccextractor is a quick hack. It could get better with time. */
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_decoders_608.h"
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include "ccx_encoders_common.h"
static unsigned int header_state;
static unsigned char psm_es_type[256];
int cc608_parity_table[256];
// LLONG processed_ccblocks = 0;
#define AVERROR_IO (-2)
#define VBI_TYPE_TELETEXT 0x1 // Teletext (uses lines 6-22 for PAL, 10-21 for NTSC)
#define VBI_TYPE_CC 0x4 // Closed Captions (line 21 NTSC, line 22 PAL)
#define VBI_TYPE_WSS 0x5 // Wide Screen Signal (line 20 NTSC, line 23 PAL)
#define VBI_TYPE_VPS 0x7 // Video Programming System (PAL) (line 16)
#define MAX_SYNC_SIZE 100000
#define PACK_START_CODE ((unsigned int)0x000001ba)
#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb)
#define SEQUENCE_END_CODE ((unsigned int)0x000001b7)
#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00)
#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100)
#define ISO_11172_END_CODE ((unsigned int)0x000001b9)
#define AV_NOPTS_VALUE ((LLONG)0x8000000000000000LL)
/* mpeg2 */
#define PROGRAM_STREAM_MAP 0x1bc
#define PRIVATE_STREAM_1 0x1bd
#define PADDING_STREAM 0x1be
#define PRIVATE_STREAM_2 0x1bf
extern struct ccx_s_write wbout1, wbout2; // Output structures
#define AUDIO_ID 0xc0
#define VIDEO_ID 0xe0
#define AC3_ID 0x80
#define DTS_ID 0x8a
#define LPCM_ID 0xa0
#define SUB_ID 0x20
#define STREAM_TYPE_VIDEO_MPEG1 0x01
#define STREAM_TYPE_VIDEO_MPEG2 0x02
#define STREAM_TYPE_AUDIO_MPEG1 0x03
#define STREAM_TYPE_AUDIO_MPEG2 0x04
#define STREAM_TYPE_PRIVATE_SECTION 0x05
#define STREAM_TYPE_PRIVATE_DATA 0x06
#define STREAM_TYPE_AUDIO_AAC 0x0f
#define STREAM_TYPE_VIDEO_MPEG4 0x10
#define STREAM_TYPE_VIDEO_H264 0x1b
#define STREAM_TYPE_AUDIO_AC3 0x81
#define STREAM_TYPE_AUDIO_DTS 0x8a
enum CodecType
{
CODEC_TYPE_UNKNOWN = -1,
CODEC_TYPE_VIDEO,
CODEC_TYPE_AUDIO,
CODEC_TYPE_DATA,
CODEC_TYPE_SUBTITLE,
};
enum CodecID
{
CODEC_ID_NONE,
CODEC_ID_MPEG1VIDEO,
CODEC_ID_MPEG2VIDEO, /* prefered ID for MPEG Video 1 or 2 decoding */
CODEC_ID_MPEG2VIDEO_XVMC,
CODEC_ID_MPEG2VIDEO_XVMC_VLD,
CODEC_ID_H261,
CODEC_ID_H263,
CODEC_ID_RV10,
CODEC_ID_RV20,
CODEC_ID_MJPEG,
CODEC_ID_MJPEGB,
CODEC_ID_LJPEG,
CODEC_ID_SP5X,
CODEC_ID_JPEGLS,
CODEC_ID_MPEG4,
CODEC_ID_RAWVIDEO,
CODEC_ID_MSMPEG4V1,
CODEC_ID_MSMPEG4V2,
CODEC_ID_MSMPEG4V3,
CODEC_ID_WMV1,
CODEC_ID_WMV2,
CODEC_ID_H263P,
CODEC_ID_H263I,
CODEC_ID_FLV1,
CODEC_ID_SVQ1,
CODEC_ID_SVQ3,
CODEC_ID_DVVIDEO,
CODEC_ID_HUFFYUV,
CODEC_ID_CYUV,
CODEC_ID_H264,
CODEC_ID_INDEO3,
CODEC_ID_VP3,
CODEC_ID_THEORA,
CODEC_ID_ASV1,
CODEC_ID_ASV2,
CODEC_ID_FFV1,
CODEC_ID_4XM,
CODEC_ID_VCR1,
CODEC_ID_CLJR,
CODEC_ID_MDEC,
CODEC_ID_ROQ,
CODEC_ID_INTERPLAY_VIDEO,
CODEC_ID_XAN_WC3,
CODEC_ID_XAN_WC4,
CODEC_ID_RPZA,
CODEC_ID_CINEPAK,
CODEC_ID_WS_VQA,
CODEC_ID_MSRLE,
CODEC_ID_MSVIDEO1,
CODEC_ID_IDCIN,
CODEC_ID_8BPS,
CODEC_ID_SMC,
CODEC_ID_FLIC,
CODEC_ID_TRUEMOTION1,
CODEC_ID_VMDVIDEO,
CODEC_ID_MSZH,
CODEC_ID_ZLIB,
CODEC_ID_QTRLE,
CODEC_ID_SNOW,
CODEC_ID_TSCC,
CODEC_ID_ULTI,
CODEC_ID_QDRAW,
CODEC_ID_VIXL,
CODEC_ID_QPEG,
CODEC_ID_XVID,
CODEC_ID_PNG,
CODEC_ID_PPM,
CODEC_ID_PBM,
CODEC_ID_PGM,
CODEC_ID_PGMYUV,
CODEC_ID_PAM,
CODEC_ID_FFVHUFF,
CODEC_ID_RV30,
CODEC_ID_RV40,
CODEC_ID_VC1,
CODEC_ID_WMV3,
CODEC_ID_LOCO,
CODEC_ID_WNV1,
CODEC_ID_AASC,
CODEC_ID_INDEO2,
CODEC_ID_FRAPS,
CODEC_ID_TRUEMOTION2,
CODEC_ID_BMP,
CODEC_ID_CSCD,
CODEC_ID_MMVIDEO,
CODEC_ID_ZMBV,
CODEC_ID_AVS,
CODEC_ID_SMACKVIDEO,
CODEC_ID_NUV,
CODEC_ID_KMVC,
CODEC_ID_FLASHSV,
CODEC_ID_CAVS,
/* various pcm "codecs" */
CODEC_ID_PCM_S16LE= 0x10000,
CODEC_ID_PCM_S16BE,
CODEC_ID_PCM_U16LE,
CODEC_ID_PCM_U16BE,
CODEC_ID_PCM_S8,
CODEC_ID_PCM_U8,
CODEC_ID_PCM_MULAW,
CODEC_ID_PCM_ALAW,
CODEC_ID_PCM_S32LE,
CODEC_ID_PCM_S32BE,
CODEC_ID_PCM_U32LE,
CODEC_ID_PCM_U32BE,
CODEC_ID_PCM_S24LE,
CODEC_ID_PCM_S24BE,
CODEC_ID_PCM_U24LE,
CODEC_ID_PCM_U24BE,
CODEC_ID_PCM_S24DAUD,
/* various adpcm codecs */
CODEC_ID_ADPCM_IMA_QT= 0x11000,
CODEC_ID_ADPCM_IMA_WAV,
CODEC_ID_ADPCM_IMA_DK3,
CODEC_ID_ADPCM_IMA_DK4,
CODEC_ID_ADPCM_IMA_WS,
CODEC_ID_ADPCM_IMA_SMJPEG,
CODEC_ID_ADPCM_MS,
CODEC_ID_ADPCM_4XM,
CODEC_ID_ADPCM_XA,
CODEC_ID_ADPCM_ADX,
CODEC_ID_ADPCM_EA,
CODEC_ID_ADPCM_G726,
CODEC_ID_ADPCM_CT,
CODEC_ID_ADPCM_SWF,
CODEC_ID_ADPCM_YAMAHA,
CODEC_ID_ADPCM_SBPRO_4,
CODEC_ID_ADPCM_SBPRO_3,
CODEC_ID_ADPCM_SBPRO_2,
/* AMR */
CODEC_ID_AMR_NB= 0x12000,
CODEC_ID_AMR_WB,
/* RealAudio codecs*/
CODEC_ID_RA_144= 0x13000,
CODEC_ID_RA_288,
/* various DPCM codecs */
CODEC_ID_ROQ_DPCM= 0x14000,
CODEC_ID_INTERPLAY_DPCM,
CODEC_ID_XAN_DPCM,
CODEC_ID_SOL_DPCM,
CODEC_ID_MP2= 0x15000,
CODEC_ID_MP3, /* prefered ID for MPEG Audio layer 1, 2 or3 decoding */
CODEC_ID_AAC,
CODEC_ID_MPEG4AAC,
CODEC_ID_AC3,
CODEC_ID_DTS,
CODEC_ID_VORBIS,
CODEC_ID_DVAUDIO,
CODEC_ID_WMAV1,
CODEC_ID_WMAV2,
CODEC_ID_MACE3,
CODEC_ID_MACE6,
CODEC_ID_VMDAUDIO,
CODEC_ID_SONIC,
CODEC_ID_SONIC_LS,
CODEC_ID_FLAC,
CODEC_ID_MP3ADU,
CODEC_ID_MP3ON4,
CODEC_ID_SHORTEN,
CODEC_ID_ALAC,
CODEC_ID_WESTWOOD_SND1,
CODEC_ID_GSM,
CODEC_ID_QDM2,
CODEC_ID_COOK,
CODEC_ID_TRUESPEECH,
CODEC_ID_TTA,
CODEC_ID_SMACKAUDIO,
CODEC_ID_QCELP,
/* subtitle codecs */
CODEC_ID_DVD_SUBTITLE= 0x17000,
CODEC_ID_DVB_SUBTITLE,
/* teletext codecs */
CODEC_ID_MPEG2VBI,
CODEC_ID_DVB_VBI,
/* DSMCC codec */
CODEC_ID_DSMCC_B,
CODEC_ID_MPEG2TS= 0x20000, /* _FAKE_ codec to indicate a raw MPEG2 transport
stream (only used by libavformat) */
};
typedef struct AVPacket
{
LLONG pts; ///< presentation time stamp in time_base units
LLONG dts; ///< decompression time stamp in time_base units
unsigned char *data;
int size;
int stream_index;
int flags;
int duration; ///< presentation duration in time_base units (0 if not available)
void (*destruct)(struct AVPacket *);
void *priv;
LLONG pos; ///< byte position in stream, -1 if unknown
int codec_id;
int type;
} 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)
{
LLONG pts;
int val;
if (c < 0)
c = get_byte(ctx);
pts = (LLONG) ((c >> 1) & 0x07) << 30;
val = get_be16(ctx);
pts |= (LLONG) (val >> 1) << 15;
val = get_be16(ctx);
pts |= (LLONG) (val >> 1);
return pts;
}
static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
unsigned int *header_state)
{
unsigned int state, v;
int val, n;
state = *header_state;
n = *size_ptr;
while (n > 0)
{
unsigned char cx;
unsigned char *cx_p = &cx;
buffered_read_byte (ctx, cx_p);
if (result!=1)
break;
ctx->past++;
v = cx;
n--;
if (state == 0x000001) {
state = ((state << 8) | v) & 0xffffff;
val = state;
goto found;
}
state = ((state << 8) | v) & 0xffffff;
}
val = -1;
found:
*header_state = state;
*size_ptr = n;
return val;
}
void url_fskip (struct lib_ccx_ctx *ctx, int length)
{
buffered_seek (ctx, length);
ctx->past+=length;
}
static long mpegps_psm_parse(struct lib_ccx_ctx *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);
/* skip program_stream_info */
url_fskip(ctx, ps_info_length);
es_map_length = 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);
/* 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 */
return 2 + psm_length;
}
static int mpegps_read_pes_header(struct lib_ccx_ctx *ctx, int *pstart_code,
LLONG *ppts, LLONG *pdts)
{
int len, size, startcode, c, flags, header_len;
LLONG pts, dts;
redo:
/* next start code (should be immediately after) */
header_state = 0xff;
size = MAX_SYNC_SIZE;
startcode = find_next_start_code(ctx, &size, &header_state);
//printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
if (startcode < 0)
return AVERROR_IO;
if (startcode == PACK_START_CODE)
goto redo;
if (startcode == SYSTEM_HEADER_START_CODE)
goto redo;
if (startcode == PADDING_STREAM ||
startcode == PRIVATE_STREAM_2)
{
/* skip them */
len = get_be16(ctx);
// url_fskip(ctx, len);
goto redo;
}
position_sanity_check();
if (startcode == PROGRAM_STREAM_MAP)
{
mpegps_psm_parse(ctx);
goto redo;
}
/* find matching stream */
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
(startcode == 0x1bd)))
goto redo;
len = get_be16(ctx);
pts = AV_NOPTS_VALUE;
dts = AV_NOPTS_VALUE;
position_sanity_check();
/* stuffing */
for(;;) {
if (len < 1)
goto redo;
c = get_byte(ctx);
len--;
/* XXX: for mpeg1, should test only bit 7 */
if (c != 0xff)
break;
}
position_sanity_check();
if ((c & 0xc0) == 0x40) {
/* buffer scale & size */
if (len < 2)
goto redo;
get_byte(ctx);
c = get_byte(ctx);
len -= 2;
}
position_sanity_check();
if ((c & 0xf0) == 0x20) {
if (len < 4)
goto redo;
dts = pts = get_pts(ctx, c);
len -= 4;
} else if ((c & 0xf0) == 0x30) {
if (len < 9)
goto redo;
pts = get_pts(ctx, c);
dts = get_pts(ctx, -1);
len -= 9;
} else if ((c & 0xc0) == 0x80) {
/* mpeg 2 PES */
#if 0 /* some streams have this field set for no apparent reason */
if ((c & 0x30) != 0) {
/* Encrypted multiplex not handled */
goto redo;
}
#endif
flags = get_byte(ctx);
header_len = get_byte(ctx);
len -= 2;
if (header_len > len)
goto redo;
if ((flags & 0xc0) == 0x80) {
dts = pts = get_pts(ctx, -1);
if (header_len < 5)
goto redo;
header_len -= 5;
len -= 5;
} if ((flags & 0xc0) == 0xc0) {
pts = get_pts(ctx, -1);
dts = get_pts(ctx, -1);
if (header_len < 10)
goto redo;
header_len -= 10;
len -= 10;
}
len -= header_len;
while (header_len > 0) {
get_byte(ctx);
header_len--;
}
}
else if( c!= 0xf )
goto redo;
position_sanity_check();
if (startcode == PRIVATE_STREAM_1 /* && psm_es_type[startcode & 0xff] */)
{
if (len < 1)
goto redo;
startcode = 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);
len -= 3;
}
}
*pstart_code = startcode;
*ppts = pts;
*pdts = dts;
return len;
}
static int cc608_good_parity(const int *parity_table, unsigned int data)
{
int ret = parity_table[data & 0xff] && parity_table[(data & 0xff00) >> 8];
if (!ret)
{
/* VERBOSE(VB_VBI, QString("VBI: Bad parity in EIA-608 data (%1)")
.arg(data,0,16)); */
}
return ret;
}
void ProcessVBIDataPacket(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
{
struct lib_cc_decode *dec_ctx = NULL;
const unsigned char *meat = av.data;
if (meat==NULL)
{
mprint ("Warning: ProcessVBIDataPacket called with NULL data, ignoring.\n");
return;
}
LLONG linemask = 0;
dec_ctx = ctx->dec_ctx;
// unsigned long long utc = lastccptsu;
// [i]tv0 means there is a linemask
// [I]TV0 means there is no linemask and all lines are present
if ((meat[0]=='t') && (meat[1]=='v') && (meat[2] == '0'))
{
/// TODO this is almost certainly not endian safe....
memcpy(&linemask, meat + 3, 8);
meat += 11;
}
else if ((meat[0]=='T') && (meat[1]=='V') && (meat[2] == '0'))
{
linemask = 0xffffffffffffffffLL;
meat += 3;
}
else
{
/* VERBOSE(VB_VBI, LOC + QString("Unknown VBI data stream '%1%2%3'")
.arg(QChar(buf[0])).arg(QChar(buf[1])).arg(QChar(buf[2]))); */
mprint (" - Unknown VBI data stream\n");
return;
}
static const unsigned int min_blank = 6;
for (unsigned int i = 0; i < 36; i++)
{
if (!((linemask >> i) & 0x1))
continue;
const unsigned int line = ((i < 18) ? i : i-18) + min_blank;
const unsigned int field = (i<18) ? 0 : 1;
const unsigned int id2 = *meat & 0xf;
switch (id2)
{
case VBI_TYPE_TELETEXT:
// SECAM lines 6-23
// PAL lines 6-22
// NTSC lines 10-21 (rare)
// ttd->Decode(buf+1, VBI_IVTV);
break;
case VBI_TYPE_CC:
// PAL line 22 (rare)
// NTSC line 21
if (21 == line)
{
int data = (meat[2] << 8) | meat[1];
if (cc608_good_parity(cc608_parity_table, data))
{
unsigned char ccdata[3];
if (field==0)
{
ccdata[0]=0x04; // Field 1
ccdata[1]=meat[1];
ccdata[2]=meat[2];
do_cb(dec_ctx, ccdata, sub);
// processed_ccblocks++; // Not sure this is accurate
}
else
{
ccdata[0]=0x05; // Field 1
ccdata[1]=meat[1];
ccdata[2]=meat[2];
do_cb(dec_ctx, ccdata, sub);
}
}
// utc += 33367;
}
break;
case VBI_TYPE_VPS: // Video Programming System
// PAL line 16
// ccd608->DecodeVPS(buf+1); // a.k.a. PDC
break;
case VBI_TYPE_WSS: // Wide Screen Signal
// PAL line 23
// NTSC line 20
// ccd608->DecodeWSS(buf+1);
break;
}
meat += 43;
}
// lastccptsu = utc;
}
static int mpegps_read_packet(struct lib_ccx_ctx *ctx)
{
LLONG pts, dts;
int len, startcode, type, codec_id = 0, es_type;
redo:
len = mpegps_read_pes_header(ctx, &startcode, &pts, &dts);
if (len < 0)
return len;
position_sanity_check();
/* now find stream */
/*
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (st->id == startcode)
goto found;
}
*/
es_type = psm_es_type[startcode & 0xff];
if(es_type > 0){
if(es_type == STREAM_TYPE_VIDEO_MPEG1){
codec_id = CODEC_ID_MPEG2VIDEO;
type = CODEC_TYPE_VIDEO;
} else if(es_type == STREAM_TYPE_VIDEO_MPEG2){
codec_id = CODEC_ID_MPEG2VIDEO;
type = CODEC_TYPE_VIDEO;
} else if(es_type == STREAM_TYPE_AUDIO_MPEG1 ||
es_type == STREAM_TYPE_AUDIO_MPEG2){
codec_id = CODEC_ID_MP3;
type = CODEC_TYPE_AUDIO;
} else if(es_type == STREAM_TYPE_AUDIO_AAC){
codec_id = CODEC_ID_AAC;
type = CODEC_TYPE_AUDIO;
} else if(es_type == STREAM_TYPE_VIDEO_MPEG4){
codec_id = CODEC_ID_MPEG4;
type = CODEC_TYPE_VIDEO;
} else if(es_type == STREAM_TYPE_VIDEO_H264){
codec_id = CODEC_ID_H264;
type = CODEC_TYPE_VIDEO;
} else if(es_type == STREAM_TYPE_AUDIO_AC3){
codec_id = CODEC_ID_AC3;
type = CODEC_TYPE_AUDIO;
} else {
goto skip;
}
}
else
if (startcode >= 0x1e0 && startcode <= 0x1ef)
{
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
unsigned char buf[8];
buffered_read (ctx, buf,8);
ctx->past+=8;
// get_buffer(&s->pb, buf, 8);
buffered_seek(ctx, -8);
ctx->past-=8;
if(!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1))
codec_id = CODEC_ID_CAVS;
else
codec_id = CODEC_ID_MPEG2VIDEO;
type = CODEC_TYPE_VIDEO;
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_MP2;
} else if (startcode >= 0x80 && startcode <= 0x87) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_AC3;
} else if (startcode >= 0x88 && startcode <= 0x9f) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_DTS;
} else if (startcode >= 0xa0 && startcode <= 0xbf) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_PCM_S16BE;
} else if (startcode >= 0x20 && startcode <= 0x3f) {
type = CODEC_TYPE_SUBTITLE;
codec_id = CODEC_ID_DVD_SUBTITLE;
} else if (startcode == 0x69 || startcode == 0x49) {
type = CODEC_TYPE_DATA;
codec_id = CODEC_ID_MPEG2VBI;
} else {
skip:
// skip packet
url_fskip(ctx, len);
goto redo;
}
// no stream found: add a new stream
/* st = av_new_stream(s, startcode);
if (!st)
goto skip;
st->codec->codec_type = type;
st->codec->codec_id = codec_id;
if (codec_id != CODEC_ID_PCM_S16BE)
st->need_parsing = 1;
// notify the callback of the change in streams
if (s->streams_changed) {
s->streams_changed(s->stream_change_data);
}
found:
if(st->discard >= AVDISCARD_ALL)
goto skip; */
if (startcode >= 0xa0 && startcode <= 0xbf)
{
// for LPCM, we just skip the header and consider it is raw
// 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)
len -= 3;
//freq = (b1 >> 4) & 3;
//st->codec->sample_rate = lpcm_freq_tab[freq];
//st->codec->channels = 1 + (b1 & 7);
//st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * 2;
}
// av_new_packet(pkt, len);
/*
printf ("Paquete de %lu bytes, codec_id=%d, type=%d\n",(unsigned long) len,
codec_id, type);
*/
//get_buffer(fh, pkt->data, pkt->size);
av.size=len;
av.data=(unsigned char *) realloc (av.data,av.size);
if (av.data==NULL)
{
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, realloc() failed. Giving up.\n");
}
av.codec_id=codec_id;
av.type=type;
buffered_read (ctx, av.data,av.size);
ctx->past+=av.size;
position_sanity_check();
// LSEEK (fh,pkt->size,SEEK_CUR);
av.pts = pts;
av.dts = dts;
// pkt->stream_index = st->index;
#if 0
av_log(s, AV_LOG_DEBUG, "%d: pts=%0.3f dts=%0.3f size=%d\n",
pkt->stream_index, pkt->pts / 90000.0, pkt->dts / 90000.0, pkt->size);
#endif
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)
{
int rc;
int has_vbi=0;
LLONG saved = 0;
struct cc_subtitle dec_sub;
struct lib_cc_decode *dec_ctx = NULL;
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);
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)
{
position_sanity_check();
if (av.codec_id==CODEC_ID_MPEG2VBI && av.type==CODEC_TYPE_DATA)
{
if (!has_vbi)
{
mprint ("\rDetected VBI data, disabling user-data packet analysis (not needed).\n");
has_vbi=1;
}
//fts_now=LLONG((processed_ccblocks*1000)/29.97);
ProcessVBIDataPacket(ctx, &dec_sub);
}
/* This needs a lot more testing */
if (av.codec_id==CODEC_ID_MPEG2VIDEO && av.type==CODEC_TYPE_VIDEO )
{
LLONG length = saved+av.size;
if (length>desp_length) // Result of a lazy programmer. Make something decent.
{
desp_length=length*2; // *2, just to reduce possible future reallocs
desp=(unsigned char *) realloc (desp,desp_length); // 16, some extra
if (!desp)
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
}
if (av.pts!=AV_NOPTS_VALUE)
{
current_pts=av.pts;
if (pts_set==0)
pts_set=1;
}
memcpy (desp+saved,av.data,av.size);
LLONG used = process_m2v(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 th=cur_sec/10;
if (ctx->last_reported_progress!=th)
{
activity_progress (-1, cur_sec/60, cur_sec%60);
ctx->last_reported_progress = th;
}
}
else
{
if (ctx->total_inputsize > 0 )
{
int progress = (int) ((((ctx->total_past+ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
if (ctx->last_reported_progress != progress)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress (progress, cur_sec/60, cur_sec%60);
fflush (stdout);
ctx->last_reported_progress = progress;
}
}
}
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
dec_sub.got_output = 0;
}
}
if (desp)
free (desp);
free (av.data);
}

963
src/lib_ccx/networking.c Normal file
View File

@@ -0,0 +1,963 @@
#include "lib_ccx.h"
#include "networking.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#define DEBUG_OUT 0
/* Protocol constants: */
#define INT_LEN 10
#define OK 1
#define PASSWORD 2
#define BIN_MODE 3
#define CC_DESC 4
#pragma warning( suppress : 4005)
#define ERROR 51
#define UNKNOWN_COMMAND 52
#define WRONG_PASSWORD 53
#define CONN_LIMIT 54
#define DFT_PORT "2048" /* Default port for server and client */
#define WRONG_PASSWORD_DELAY 2 /* Seconds */
#define BUFFER_SIZE 50
int srv_sd = -1; /* Server socket descriptor */
/*
* 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);
/*
* Writes/reads data according to protocol to descriptor
* block format: * command | lenght | data | \r\n
* 1 byte | INT_LEN bytes | lenght bytes | 2 bytes
*/
ssize_t write_block(int fd, char command, const char *buf, size_t buf_len);
ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len);
/* Reads n bytes from descriptor */
ssize_t readn(int fd, void *vptr, size_t n);
/* Writes n bytes to descriptor */
ssize_t writen(int fd, const void *vptr, size_t n);
/* Convinence functions */
ssize_t write_byte(int fd, char status);
ssize_t read_byte(int fd, char *status);
void init_sockets (void);
#if DEBUG_OUT
void pr_command(char c);
#endif
void connect_to_srv(const char *addr, const char *port, const char *cc_desc)
{
if (NULL == addr)
{
mprint("Server addres is not set\n");
fatal(EXIT_FAILURE, "Unable to connect\n");
}
if (NULL == port)
port = DFT_PORT;
mprint("\n\r----------------------------------------------------------------------\n");
mprint("Connecting to %s:%s\n", addr, port);
if ((srv_sd = tcp_connect(addr, port)) < 0)
fatal(EXIT_FAILURE, "Unable to connect\n");
if (ask_passwd(srv_sd) < 0)
fatal(EXIT_FAILURE, "Unable to connect\n");
if (cc_desc != NULL &&
write_block(srv_sd, CC_DESC, cc_desc, strlen(cc_desc)) < 0)
{
fatal(EXIT_FAILURE, "Unable to connect\n");
}
mprint("Connected to %s:%s\n", addr, port);
}
void net_send_header(const unsigned char *data, size_t len)
{
assert(srv_sd > 0);
#if DEBUG_OUT
fprintf(stderr, "Sending header (len = %u): \n", 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)
{
printf("Can't send BIN header\n");
return;
}
char ok;
if (read_byte(srv_sd, &ok) != 1)
return;
#if DEBUG_OUT
fprintf(stderr, "[S] ");
pr_command(ok);
fprintf(stderr, "\n");
#endif
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;
}
}
void net_send_cc(const unsigned char *data, size_t len)
{
assert(srv_sd > 0);
#if DEBUG_OUT
fprintf(stderr, "[C] Sending %u bytes\n", len);
#endif
ssize_t rc;
if ((rc = writen(srv_sd, data, len)) != (int) len)
{
if (rc < 0)
mprint("write() error: %s", strerror(errno));
return;
}
/* nanosleep((struct timespec[]){{0, 100000000}}, NULL); */
/* Sleep(100); */
return;
}
/*
* command | lenght | data | \r\n
* 1 byte | INT_LEN bytes | lenght bytes | 2 bytes
*/
ssize_t write_block(int fd, char command, const char *buf, size_t buf_len)
{
assert(fd > 0);
#if DEBUG_OUT
fprintf(stderr, "[C] ");
#endif
int rc;
ssize_t nwritten = 0;
if ((rc = write_byte(fd, command)) < 0)
return -1;
else if (rc != 1)
return 0;
nwritten++;
#if DEBUG_OUT
pr_command(command);
fprintf(stderr, " ");
#endif
char len_str[INT_LEN] = {0};
snprintf(len_str, INT_LEN, "%zu", buf_len);
if ((rc = writen(fd, len_str, INT_LEN)) < 0)
return -1;
else if (rc != INT_LEN)
return 0;
nwritten += rc;
#if DEBUG_OUT
fwrite(len_str, sizeof(char), INT_LEN, stderr);
fprintf(stderr, " ");
#endif
if (buf_len > 0)
{
if ((rc = writen(fd, buf, buf_len)) < 0)
return -1;
else if (rc != (int) buf_len)
return 0;
nwritten += rc;
}
#if DEBUG_OUT
if (buf != NULL)
{
fwrite(buf, sizeof(char), buf_len, stderr);
fprintf(stderr, " ");
}
#endif
if ((rc = write_byte(fd, '\r')) < 0)
return -1;
else if (rc != 1)
return 0;
nwritten++;
#if DEBUG_OUT
fprintf(stderr, "\\r");
#endif
if ((rc = write_byte(fd, '\n')) < 0)
return -1;
else if (rc != 1)
return 0;
nwritten++;
#if DEBUG_OUT
fprintf(stderr, "\\n\n");
#endif
return nwritten;
}
int tcp_connect(const char *host, const char *port)
{
assert(host != NULL);
assert(port != NULL);
init_sockets();
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
struct addrinfo *ai;
int rc = getaddrinfo(host, port, &hints, &ai);
if (rc != 0) {
mprint("getaddrinfo() error: %s\n", gai_strerror(rc));
return -1;
}
struct addrinfo *p;
int sockfd;
/* Try each address until we sucessfully connect */
for (p = ai; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, SOCK_STREAM, p->ai_protocol);
if (-1 == sockfd) {
#if _WIN32
wprintf(L"socket() eror: %ld\n", WSAGetLastError());
#else
mprint("socket() error: %s\n", strerror(errno));
#endif
if (p->ai_next != NULL)
mprint("trying next addres ...\n");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0)
break;
#if _WIN32
wprintf(L"connect() eror: %ld\n", WSAGetLastError());
#else
mprint("connect() error: %s\n", strerror(errno));
#endif
if (p->ai_next != NULL)
mprint("trying next addres ...\n");
#if _WIN32
closesocket(sockfd);
#else
close(sockfd);
#endif
}
freeaddrinfo(ai);
if (NULL == p)
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)
port = DFT_PORT;
mprint("\n\r----------------------------------------------------------------------\n");
mprint("Binding to %s\n", port);
int fam;
int listen_sd = tcp_bind(port, &fam);
if (listen_sd < 0)
fatal(EXIT_FAILURE, "Unable to start server\n");
if (pwd != NULL)
mprint("Password: %s\n", pwd);
mprint("Waiting for connections\n");
int sockfd = -1;
while (1)
{
socklen_t clilen;
if (AF_INET == fam)
clilen = sizeof(struct sockaddr_in);
else
clilen = sizeof(struct sockaddr_in6);
struct sockaddr *cliaddr = (struct sockaddr *) malloc(clilen);
if (NULL == cliaddr)
fatal(EXIT_FAILURE, "malloc() error: %s", strerror(errno));
if ((sockfd = accept(listen_sd, cliaddr, &clilen)) < 0)
{
if (EINTR == errno) /* TODO not necessary */
{
continue;
}
else
{
#if _WIN32
wprintf(L"accept() eror: %ld\n", WSAGetLastError());
exit(EXIT_FAILURE);
#else
fatal(EXIT_FAILURE, "accept() error: %s\n", strerror(errno));
#endif
}
}
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
int rc;
if ((rc = getnameinfo(cliaddr, clilen,
host, sizeof(host), serv, sizeof(serv), 0)) != 0)
{
mprint("getnameinfo() error: %s\n", gai_strerror(rc));
}
else
{
mprint("%s:%s Connceted\n", host, serv);
}
free(cliaddr);
if (pwd != NULL && (rc = check_password(sockfd, pwd)) <= 0)
goto close_conn;
#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);
#else
close(sockfd);
#endif
}
#if _WIN32
closesocket(listen_sd);
#else
close(listen_sd);
#endif
return sockfd;
}
int check_password(int fd, const char *pwd)
{
assert(pwd != NULL);
char c;
int rc;
size_t len;
char buf[BUFFER_SIZE];
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 (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;
}
return 1;
}
}
int tcp_bind(const char *port, int *family)
{
init_sockets();
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
struct addrinfo *ai;
int rc = getaddrinfo(NULL, port, &hints, &ai);
if (rc != 0)
{
mprint("getaddrinfo() error: %s\n", gai_strerror(rc));
return -1;
}
struct addrinfo *p;
int sockfd = -1;
/* Try each address until we sucessfully bind */
for (p = ai; p != NULL; p = p->ai_next)
{
sockfd = socket(p->ai_family, SOCK_STREAM, p->ai_protocol);
if (-1 == sockfd)
{
#if _WIN32
wprintf(L"socket() eror: %ld\n", WSAGetLastError());
#else
mprint("socket() error: %s\n", strerror(errno));
#endif
if (p->ai_next != NULL)
mprint("trying next addres ...\n");
continue;
}
if (AF_INET6 == p->ai_family)
{
int no = 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) < 0)
{
#if _WIN32
wprintf(L"setsockopt() eror: %ld\n", WSAGetLastError());
#else
mprint("setsockopt() error: %s\n", strerror(errno));
#endif
if (p->ai_next != NULL)
mprint("trying next addres ...\n");
continue;
}
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) < 0)
{
#if _WIN32
wprintf(L"bind() error: %ld\n", WSAGetLastError());
closesocket(sockfd);
#else
mprint("bind() error: %s\n", strerror(errno));
close(sockfd);
#endif
if (p->ai_next != NULL)
mprint("trying next addres ...\n");
continue;
}
*family = p->ai_family;
break;
}
freeaddrinfo(ai);
if (NULL == p)
return -1;
if (listen(sockfd, SOMAXCONN) != 0)
{
#if _WIN32
wprintf(L"listen() eror: %ld\n", WSAGetLastError());
closesocket(sockfd);
#else
perror("listen() error");
close(sockfd);
#endif
return -1;
}
return sockfd;
}
ssize_t read_block(int fd, char *command, char *buf, size_t *buf_len)
{
assert(command != NULL);
assert(buf != NULL);
assert(buf_len != NULL);
assert(*buf_len > 0);
ssize_t rc;
ssize_t nread = 0;
if ((rc = readn(fd, command, 1)) < 0)
return -1;
else if ((size_t) rc != 1)
return 0;
nread += rc;
#if DEBUG_OUT
fprintf(stderr, "[C] ");
pr_command(*command);
fprintf(stderr, " ");
#endif
char len_str[INT_LEN] = {0};
if ((rc = readn(fd, len_str, INT_LEN)) < 0)
return -1;
else if (rc != INT_LEN)
return 0;
nread += rc;
#if DEBUG_OUT
fwrite(len_str, sizeof(char), INT_LEN, stderr);
fprintf(stderr, " ");
#endif
size_t len = atoi(len_str);
if (len > 0)
{
size_t ign_bytes = 0;
if (len > *buf_len)
{
ign_bytes = len - *buf_len;
mprint("read_block() warning: Buffer overflow, ignoring %d bytes\n",
ign_bytes);
len = *buf_len;
}
if ((rc = readn(fd, buf, len)) < 0)
return -1;
else if ((size_t) rc != len)
return 0;
nread += rc;
*buf_len = len;
if ((rc = readn(fd, 0, ign_bytes)) < 0)
return -1;
else if ((size_t) rc != ign_bytes)
return 0;
nread += rc;
#if DEBUG_OUT
fwrite(buf, sizeof(char), len, stderr);
fprintf(stderr, " ");
#endif
}
char end[2] = {0};
if ((rc = readn(fd, end, sizeof(end))) < 0)
return -1;
else if ((size_t) rc != sizeof(end))
return 0;
nread += rc;
if (end[0] != '\r' || end[1] != '\n')
{
#if DEBUG_OUT
fprintf(stderr, "read_block(): No end marker present\n");
fprintf(stderr, "Closing connection\n");
#endif
return 0;
}
#if DEBUG_OUT
fprintf(stderr, "\\r\\n\n");
#endif
return nread;
}
#if DEBUG_OUT
void pr_command(char c)
{
switch(c)
{
case OK:
fprintf(stderr, "OK");
break;
case BIN_MODE:
fprintf(stderr, "BIN_MODE");
break;
case WRONG_PASSWORD:
fprintf(stderr, "WRONG_PASSWORD");
break;
case UNKNOWN_COMMAND:
fprintf(stderr, "UNKNOWN_COMMAND");
break;
case ERROR:
fprintf(stderr, "ERROR");
break;
case CONN_LIMIT:
fprintf(stderr, "CONN_LIMIT");
break;
case PASSWORD:
fprintf(stderr, "PASSWORD");
break;
default:
fprintf(stderr, "UNKNOWN (%d)", (int) c);
break;
}
}
#endif
ssize_t readn(int fd, void *vptr, size_t n)
{
assert(fd > 0);
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
if (NULL == vptr) {
char c;
nread = recv(fd, &c, 1, 0);
}
else
{
nread = recv(fd, (void*)ptr, nleft, 0);
}
if (nread < 0)
{
if (errno == EINTR)
{
nread = 0;
}
else
{
#if _WIN32
wprintf(L"recv() eror: %ld\n", WSAGetLastError());
#else
mprint("recv() error: %s\n", strerror(errno));
#endif
return -1;
}
}
else if (0 == nread)
{
break; /* EOF */
}
nleft -= nread;
ptr += nread;
}
return n - nleft;
}
ssize_t writen(int fd, const void *vptr, size_t n)
{
assert(fd > 0);
assert((n > 0 && vptr != NULL) || (n == 0 && vptr == NULL));
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
if ((nwritten = send(fd, ptr, nleft, 0)) < 0)
{
if (errno == EINTR)
{
nwritten = 0;
}
else
{
#if _WIN32
wprintf(L"send() eror: %ld\n", WSAGetLastError());
#else
mprint("send() error: %s\n", strerror(errno));
#endif
return -1;
}
}
else if (0 == nwritten)
{
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
ssize_t write_byte(int fd, char ch)
{
assert(fd > 0);
return writen(fd, &ch, 1);
}
ssize_t read_byte(int fd, char *ch)
{
assert(fd > 0);
assert(ch != NULL);
return readn(fd, ch, 1);
}
int start_upd_srv(const char *addr_str, unsigned port)
{
init_sockets();
in_addr_t addr;
if (addr_str != NULL)
{
struct hostent *host = gethostbyname(addr_str);
if (NULL == host)
{
fatal(EXIT_MALFORMED_PARAMETER, "Cannot look up udp network address: %s\n",
addr_str);
}
else if (host->h_addrtype != AF_INET)
{
fatal(EXIT_MALFORMED_PARAMETER, "No support for non-IPv4 network addresses: %s\n",
addr_str);
}
addr = ntohl(((struct in_addr *)host->h_addr_list[0])->s_addr);
}
else
{
addr = INADDR_ANY;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd) {
#if _WIN32
wprintf(L"socket() eror: %ld\n", WSAGetLastError());
exit(EXIT_FAILURE);
#else
mprint("socket() error: %s\n", strerror(errno));
#endif
}
if (IN_MULTICAST(addr))
{
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
{
#if _WIN32
wprintf(L"setsockopt() error: %ld\n", WSAGetLastError());
#else
mprint("setsockopt() error: %s\n", strerror(errno));
#endif
}
}
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
if (IN_MULTICAST(addr))
servaddr.sin_addr.s_addr = htonl(addr);
else
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
{
#if _WIN32
wprintf(L"bind() error: %ld\n", WSAGetLastError());
exit(EXIT_FAILURE);
#else
fatal(CCX_COMMON_EXIT_BUG_BUG, "bind() error: %s\n", strerror(errno));
#endif
}
if (IN_MULTICAST(addr)) {
struct ip_mreq group;
group.imr_multiaddr.s_addr = htonl(addr);
group.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
#if _WIN32
wprintf(L"setsockopt() error: %ld\n", WSAGetLastError());
#else
mprint("setsockopt() error: %s\n", strerror(errno));
#endif
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot join multicast group.");
}
}
mprint("\n\r----------------------------------------------------------------------\n");
if (addr == INADDR_ANY)
{
mprint("\rReading from UDP socket %u\n", port);
}
else
{
struct in_addr in;
in.s_addr = htonl(addr);
mprint("\rReading from UDP socket %s:%u\n", inet_ntoa(in), port);
}
return sockfd;
}
void init_sockets (void)
{
static int socket_inited = 0;
if (!socket_inited)
{
// Initialize Winsock
#ifdef _WIN32
WSADATA wsaData = {0};
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
wprintf(L"WSAStartup failed: %d\n", iResult);
exit(EXIT_FAILURE);
}
#endif
socket_inited = 1;
}
}

15
src/lib_ccx/networking.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef NETWORKING_H
#define NETWORKING_H
#include <sys/types.h>
void connect_to_srv(const char *addr, const char *port, const char *cc_desc);
void net_send_header(const unsigned char *data, size_t len);
void net_send_cc(const unsigned char *data, size_t len);
int start_tcp_srv(const char *port, const char *pwd);
int start_upd_srv(const char *addr, unsigned port);
#endif /* end of include guard: NETWORKING_H */

329
src/lib_ccx/ocr.c Normal file
View File

@@ -0,0 +1,329 @@
#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"
struct ocrCtx
{
TessBaseAPI* api;
};
struct transIntensity
{
uint8_t *t;
png_color *palette;
};
static int check_trans_tn_intensity(const void *p1, const void *p2, void *arg)
{
struct transIntensity *ti = arg;
unsigned char* tmp = (unsigned char*)p1;
unsigned char* act = (unsigned char*)p2;
unsigned char tmp_i;
unsigned char act_i;
/** TODO verify that RGB follow ITU-R BT.709
* Below fomula is valid only for 709 standurd
* Y = 0.2126 R + 0.7152 G + 0.0722 B
*/
tmp_i = (0.2126 * ti->palette[*tmp].red) + (0.7152 * ti->palette[*tmp].green) + (0.0722 * ti->palette[*tmp].blue);
act_i = (0.2126 * ti->palette[*act].red) + (0.7152 * ti->palette[*act].green) + (0.0722 * ti->palette[*act].blue);;
if (ti->t[*tmp] < ti->t[*act] || (ti->t[*tmp] == ti->t[*act] && tmp_i < act_i))
return -1;
else if (ti->t[*tmp] == ti->t[*act] && tmp_i == act_i)
return 0;
return 1;
}
static int search_language_pack(const char *dirname,const char *lang)
{
DIR *dp;
struct dirent *dirp;
char filename[256];
if ((dp = opendir(dirname)) == NULL)
{
return -1;
}
snprintf(filename, 256, "%s.traineddata",lang);
while ((dirp = readdir(dp)) != NULL)
{
if(!strcmp(dirp->d_name, filename))
{
closedir(dp);
return 0;
}
}
closedir(dp);
return -1;
}
static void delete_ocr (struct ocrCtx* ctx)
{
TessBaseAPIEnd(ctx->api);
TessBaseAPIDelete(ctx->api);
freep(&ctx);
}
void* init_ocr(int lang_index)
{
int ret;
struct ocrCtx* ctx;
ctx = (struct ocrCtx*)malloc(sizeof(struct ocrCtx));
if(!ctx)
return NULL;
ctx->api = TessBaseAPICreate();
/* if language was undefined use english */
if(lang_index == 0)
{
/* select english */
lang_index = 1;
}
/* if langauge pack not found use english */
ret = search_language_pack("tessdata",language[lang_index]);
if(ret < 0 )
{
/* select english */
lang_index = 1;
}
ret = TessBaseAPIInit3(ctx->api,"", language[lang_index]);
if(ret < 0)
{
goto fail;
}
return ctx;
fail:
delete_ocr(ctx);
return NULL;
}
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h)
{
PIX *pix;
char*text_out= NULL;
int i,j,index;
unsigned int wpl;
unsigned int *data,*ppixel;
struct ocrCtx* ctx = arg;
pix = pixCreate(w, h, 32);
if(pix == NULL)
{
return NULL;
}
wpl = pixGetWpl(pix);
data = pixGetData(pix);
#if LEPTONICA_VERSION > 69
pixSetSpp(pix, 4);
#endif
for (i = 0; i < h; i++)
{
ppixel = data + i * wpl;
for (j = 0; j < w; j++)
{
index = indata[i * w + (j)];
composeRGBPixel(palette[index].red, palette[index].green,palette[index].blue, ppixel);
SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL,alpha[index]);
ppixel++;
}
}
text_out = TessBaseAPIProcessPage(ctx->api, pix, 0, NULL, NULL, 0);
if(!text_out)
printf("\nsomething messy\n");
//TessDeleteText(text_out);
pixDestroy(&pix);
return text_out;
}
/*
* @param alpha out
* @param intensity in
* @param palette out should be already initialized
* @param bitmap in
* @param size in size of bitmap
* @param max_color in
* @param nb_color in
*/
static int quantize_map(png_byte *alpha, png_color *palette,
uint8_t *bitmap, int size, int max_color, int nb_color)
{
/*
* occurrence of color in image
*/
uint32_t *histogram = NULL;
/* intensity ordered table */
uint8_t *iot = NULL;
/* array of color with most occurrence according to histogram
* save index of intensity order table
*/
uint32_t *mcit = NULL;
struct transIntensity ti = { alpha,palette};
int ret = 0;
histogram = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
if (!histogram)
{
ret = -1;
goto end;
}
iot = (uint8_t*) malloc(nb_color * sizeof(uint8_t));
if (!iot)
{
ret = -1;
goto end;
}
mcit = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
if (!mcit)
{
ret = -1;
goto end;
}
memset(histogram, 0, nb_color * sizeof(uint32_t));
/* initializing intensity ordered table with serial order of unsorted color table */
for (int i = 0; i < nb_color; i++)
{
iot[i] = i;
}
memset(mcit, 0, nb_color * sizeof(uint32_t));
/* calculate histogram of image */
for (int i = 0; i < size; i++)
{
histogram[bitmap[i]]++;
}
/* sorted in increasing order of intensity */
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
#if OCR_DEBUG
ccx_common_logging.log_ftn("Intensity ordered table\n");
for (int i = 0; i < nb_color; i++)
{
ccx_common_logging.log_ftn("%02d) map %02d hist %02d\n",
i, iot[i], histogram[iot[i]]);
}
#endif
/**
* using selection sort since need to find only max_color
* Hostogram becomes invalid in this loop
*/
for (int i = 0; i < max_color; i++)
{
uint32_t max_val = 0;
uint32_t max_ind = 0;
int j;
for (j = 0; j < nb_color; j++)
{
if (max_val < histogram[iot[j]])
{
max_val = histogram[iot[j]];
max_ind = j;
}
}
for (j = i; j > 0 && max_ind < mcit[j - 1]; j--)
{
mcit[j] = mcit[j - 1];
}
mcit[j] = max_ind;
histogram[iot[max_ind]] = 0;
}
#if OCR_DEBUG
ccx_common_logging.log_ftn("max redundant intensities table\n");
for (int i = 0; i < max_color; i++)
{
ccx_common_logging.log_ftn("%02d) mcit %02d\n",
i, mcit[i]);
}
#endif
for (int i = 0, mxi = 0; i < nb_color; i++)
{
int step, inc;
if (i == mcit[mxi])
{
mxi = (mxi < max_color) ? mxi + 1 : mxi;
continue;
}
inc = (mxi) ? -1 : 0;
step = mcit[mxi + inc] + ((mcit[mxi] - mcit[mxi + inc]) / 2);
if (i <= step)
{
int index = iot[mcit[mxi + inc]];
alpha[iot[i]] = alpha[index];
palette[iot[i]].red = palette[index].red;
palette[iot[i]].blue = palette[index].blue;
palette[iot[i]].green = palette[index].green;
}
else
{
int index = iot[mcit[mxi]];
alpha[iot[i]] = alpha[index];
palette[iot[i]].red = palette[index].red;
palette[iot[i]].blue = palette[index].blue;
palette[iot[i]].green = palette[index].green;
}
}
#if OCR_DEBUG
ccx_common_logging.log_ftn("Colors present in quantized Image\n");
for (int i = 0; i < nb_color; i++)
{
ccx_common_logging.log_ftn("%02d)r %03d g %03d b %03d a %03d\n",
i, palette[i].red, palette[i].green, palette[i].blue, alpha[i]);
}
#endif
end: freep(&histogram);
freep(&mcit);
freep(&iot);
return ret;
}
int ocr_rect(void* arg, struct cc_bitmap *rect, char **str)
{
int ret = 0;
png_color *palette = NULL;
png_byte *alpha = NULL;
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
if(!palette)
{
ret = -1;
goto end;
}
alpha = (png_byte*) malloc(rect[0].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;
}
#else
char* ocr_bitmap(png_color *palette,png_byte *alpha, unsigned char* indata,unsigned char d,int w, int h)
{
mprint("ocr not supported without tesseract\n");
return NULL;
}
#endif

9
src/lib_ccx/ocr.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef OCR_H
#define OCR_H
#include <png.h>
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);
#endif

View File

@@ -1,24 +1,27 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#ifdef _WIN32
#include <io.h>
#else
#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)
void init_write (struct ccx_s_write *wb,char *filename)
{
memset(wb, 0, sizeof(struct ccx_s_write));
wb->fh=-1;
wb->filename=NULL;
}
wb->filename=filename;
}
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb)
{
write (wb->fh,data,length);
}
void writedata(const unsigned char *data, int length, struct s_context_cc608 *context)
void writedata(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub)
{
// Don't do anything for empty data
if (data==NULL)
@@ -26,24 +29,24 @@ void writedata(const unsigned char *data, int length, struct s_context_cc608 *co
if (ccx_options.write_format==CCX_OF_RAW || ccx_options.write_format==CCX_OF_DVDRAW)
{
if (context->out)
if (context && context->out)
writeraw (data,length,context->out);
}
else if (ccx_options.write_format==CCX_OF_SMPTETT ||
else if (ccx_options.write_format==CCX_OF_SMPTETT ||
ccx_options.write_format==CCX_OF_SAMI ||
ccx_options.write_format==CCX_OF_SRT ||
ccx_options.write_format==CCX_OF_TRANSCRIPT ||
ccx_options.write_format==CCX_OF_SPUPNG ||
ccx_options.write_format==CCX_OF_NULL)
process608 (data,length,context);
process608 (data,length,context, sub);
else
fatal(EXIT_BUG_BUG, "Should not be reached!");
fatal(CCX_COMMON_EXIT_BUG_BUG, "Should not be reached!");
}
void flushbuffer (struct ccx_s_write *wb, int closefile)
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile)
{
if (closefile && wb!=NULL && wb->fh!=-1 && !cc_to_stdout)
close (wb->fh);
if (closefile && wb!=NULL && wb->fh!=-1 && !ctx->cc_to_stdout)
close (wb->fh);
}
void writeDVDraw (const unsigned char *data1, int length1,
@@ -51,7 +54,7 @@ void writeDVDraw (const unsigned char *data1, int length1,
struct ccx_s_write *wb)
{
/* these are only used by DVD raw mode: */
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
loop 3: 11 elements, rest: 15 elements */
static int datacount = 0; /* counts within loop */
@@ -65,26 +68,26 @@ void writeDVDraw (const unsigned char *data1, int length1,
if (loopcount==3)
{
write (wb->fh,lc3,sizeof (lc3));
if (data2 && length2)
if (data2 && length2)
write (wb->fh,data2,length2);
}
if (loopcount>3)
{
write (wb->fh,lc4,sizeof (lc4));
if (data2 && length2)
if (data2 && length2)
write (wb->fh,data2,length2);
}
}
datacount++;
write (wb->fh,lc5,sizeof (lc5));
if (data1 && length1)
if (data1 && length1)
write (wb->fh,data1,length1);
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
((loopcount > 3) && (datacount < 15)))
{
write (wb->fh,lc6,sizeof (lc6));
if (data2 && length2)
if (data2 && length2)
write (wb->fh,data2,length2);
}
else
@@ -92,46 +95,52 @@ void writeDVDraw (const unsigned char *data1, int length1,
if (loopcount==1)
{
write (wb->fh,lc6,sizeof (lc6));
if (data2 && length2)
if (data2 && length2)
write (wb->fh,data2,length2);
}
loopcount++;
datacount=0;
}
}
void printdata (const unsigned char *data1, int length1,
const unsigned char *data2, int length2)
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
const unsigned char *data2, int length2, struct cc_subtitle *sub)
{
if (ccx_options.write_format==CCX_OF_DVDRAW)
writeDVDraw (data1,length1,data2,length2,&wbout1);
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);
else /* Broadcast raw or any non-raw */
{
if (length1 && ccx_options.extract!=2)
{
writedata(data1, length1, &context_cc608_field_1);
}
if (length2)
{
if (length1 && ccx_options.extract != 2)
{
if (ccx_options.extract!=1)
writedata(data2, length2, &context_cc608_field_2);
writedata(data1, length1, field_1, sub);
}
if (length2)
{
if (ccx_options.extract != 1)
writedata(data2, length2, field_2, sub);
else // User doesn't want field 2 data, but we want XDS.
writedata (data2,length2,NULL);
}
}
writedata (data2,length2,NULL, sub);
}
}
}
/* Buffer data with the same FTS and write when a new FTS or data==NULL
* is encountered */
void writercwtdata (const unsigned char *data)
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data)
{
static LLONG prevfts = -1;
LLONG currfts = fts_now + 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];
static LLONG prevfts = -1;
LLONG currfts = fts_now + 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
@@ -178,8 +187,16 @@ void writercwtdata (const unsigned char *data)
if (cbcount > 0)
{
writeraw(cbheader,10,&wbout1);
writeraw(cbbuffer,3*cbcount, &wbout1);
if (ccx_options.send_to_srv)
{
net_send_cc(cbheader, 10);
net_send_cc(cbbuffer, 3*cbcount);
}
else
{
writeraw(cbheader,10,wbout1);
writeraw(cbbuffer,3*cbcount, wbout1);
}
}
cbcount = 0;
cbempty = 0;
@@ -187,7 +204,7 @@ void writercwtdata (const unsigned char *data)
if ( data )
{
// Store the data while the FTS is unchanged
// Store the data while the FTS is unchanged
unsigned char cc_valid = (*data & 4) >> 2;
unsigned char cc_type = *data & 3;
@@ -222,8 +239,16 @@ void writercwtdata (const unsigned char *data)
memcpy(cbbuffer, "\x04\x80\x80", 3); // Field 1 padding
memcpy(cbbuffer+3, "\x05\x80\x80", 3); // Field 2 padding
writeraw(cbheader,10,&wbout1);
writeraw(cbbuffer,3*cbcount, &wbout1);
if (ccx_options.send_to_srv)
{
net_send_cc(cbheader, 10);
net_send_cc(cbbuffer, 3*cbcount);
}
else
{
writeraw(cbheader,10, wbout1);
writeraw(cbbuffer,3*cbcount, wbout1);
}
cbcount = 0;
cbempty = 0;

1675
src/lib_ccx/params.c Normal file

File diff suppressed because it is too large Load Diff

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