mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-02-12 05:25:06 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f3e5fe677 | ||
|
|
ad99ccdfec | ||
|
|
1bc174efa2 | ||
|
|
983db8c92d | ||
|
|
b4ce115f7c | ||
|
|
cb7f31ef8c | ||
|
|
1a5d78b1b4 | ||
|
|
c873ff6a06 | ||
|
|
454024808d | ||
|
|
0a22e1e429 | ||
|
|
3fb288357d | ||
|
|
966d88fc10 | ||
|
|
c91aa79852 | ||
|
|
04ccb477f1 | ||
|
|
10ea570229 | ||
|
|
551c3d0e2f | ||
|
|
49530b079b | ||
|
|
02986fe7a8 | ||
|
|
a230ec5f6f | ||
|
|
7902b85d1b | ||
|
|
77d275d6a5 | ||
|
|
4c2a4a59a2 | ||
|
|
d80455a408 | ||
|
|
27e2bb9017 | ||
|
|
9358978a61 | ||
|
|
cffd02c106 | ||
|
|
b45370cbb4 | ||
|
|
56e15a3be0 | ||
|
|
7b4d93988f | ||
|
|
0e803eba95 | ||
|
|
8c9bfa17dd | ||
|
|
413173f5e5 | ||
|
|
1a050c76a5 | ||
|
|
c3d00d80f5 | ||
|
|
c989c941df | ||
|
|
dc9f6d250a |
@@ -1,12 +1,12 @@
|
||||
ccextractor
|
||||
===========
|
||||
|
||||
Carlos' version (mainstream) is most stable branch.
|
||||
Carlos' version (mainstream) is the most stable branch.
|
||||
|
||||
Extracting subtitles were never so easy then following command:
|
||||
Extracting subtitles has never been so easy. Just type the following command:
|
||||
ccextrator "name of input"
|
||||
|
||||
Gui lovers please download Sorceforge version of CCExtractor, Git Version is not your cup of tea.
|
||||
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
|
||||
|
||||
219
docs/CHANGES.TXT
219
docs/CHANGES.TXT
@@ -1,5 +1,11 @@
|
||||
0.75
|
||||
-----------
|
||||
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
|
||||
@@ -7,8 +13,8 @@
|
||||
builds don't add it (because it messes with text processing tools).
|
||||
You can use -bom and -nobom to change the behaviour.
|
||||
|
||||
0.74
|
||||
-----------
|
||||
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
|
||||
@@ -17,19 +23,19 @@
|
||||
- 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
|
||||
-----------
|
||||
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
|
||||
-----------
|
||||
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
|
||||
-----------
|
||||
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
|
||||
@@ -39,8 +45,8 @@
|
||||
- Fix for .bin files when not using latin1 charset
|
||||
- Correction of mp4 timing, when one timestamp points timing of two atom
|
||||
|
||||
0.70 - GSOC
|
||||
-----------
|
||||
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
|
||||
@@ -80,8 +86,8 @@ version of CCExtractor.
|
||||
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.
|
||||
@@ -100,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.
|
||||
@@ -115,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.
|
||||
@@ -136,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
|
||||
@@ -215,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)
|
||||
@@ -234,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
|
||||
@@ -255,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
|
||||
@@ -264,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
|
||||
@@ -287,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.
|
||||
@@ -298,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.
|
||||
@@ -309,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.
|
||||
@@ -338,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.
|
||||
@@ -363,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.
|
||||
@@ -389,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
|
||||
@@ -403,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.
|
||||
@@ -430,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
|
||||
@@ -456,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,
|
||||
@@ -480,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.
|
||||
@@ -494,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
|
||||
@@ -516,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
|
||||
@@ -528,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
|
||||
@@ -537,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.
|
||||
@@ -558,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.
|
||||
@@ -599,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
|
||||
@@ -630,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.
|
||||
@@ -640,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
|
||||
@@ -692,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
|
||||
@@ -712,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,
|
||||
@@ -732,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.
|
||||
@@ -741,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.
|
||||
@@ -763,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
|
||||
@@ -786,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).
|
||||
@@ -801,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
|
||||
@@ -813,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
|
||||
@@ -831,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
|
||||
@@ -843,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
|
||||
@@ -852,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
|
||||
@@ -866,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).
|
||||
|
||||
2
mac/build.command
Normal file → Executable file
2
mac/build.command
Normal file → Executable file
@@ -1 +1 @@
|
||||
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') $(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
|
||||
|
||||
@@ -182,7 +182,8 @@ int main(int argc, char *argv[])
|
||||
strcpy (ctx->basefilename, ctx->basefilename_for_network);
|
||||
break;
|
||||
}
|
||||
for (c=ctx->basefilename+strlen (ctx->basefilename)-1; ctx->basefilename &&
|
||||
|
||||
for (c = ctx->basefilename + strlen(ctx->basefilename) - 1; c>ctx->basefilename &&
|
||||
*c!='.'; c--) {;} // Get last .
|
||||
if (*c=='.')
|
||||
*c=0;
|
||||
@@ -268,6 +269,7 @@ int main(int argc, char *argv[])
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_RAW:
|
||||
init_encoder(enc_ctx, &ctx->wbout1);
|
||||
writeraw(BROADCAST_HEADER, sizeof(BROADCAST_HEADER), &ctx->wbout1);
|
||||
break;
|
||||
case CCX_OF_DVDRAW:
|
||||
|
||||
@@ -259,8 +259,8 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,10 @@ void init_options (struct ccx_s_options *options)
|
||||
/* 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;
|
||||
@@ -91,6 +95,7 @@ void init_options (struct ccx_s_options *options)
|
||||
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);
|
||||
|
||||
@@ -53,6 +53,10 @@ struct ccx_s_options // Options from user parameters
|
||||
/* 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;
|
||||
@@ -86,6 +90,7 @@ struct ccx_s_options // Options from user parameters
|
||||
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
|
||||
|
||||
@@ -99,6 +99,7 @@ struct lib_cc_decode
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
@@ -427,7 +427,8 @@ static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
// whole sequence info.
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -85,6 +85,16 @@ void prepare_for_new_file (struct lib_ccx_ctx *ctx)
|
||||
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 */
|
||||
@@ -246,7 +256,7 @@ void buffered_seek (struct lib_ccx_ctx *ctx, int offset)
|
||||
if (filebuffer_pos<0)
|
||||
{
|
||||
// We got into the start buffer (hopefully)
|
||||
if (ctx->startbytes_pos+filebuffer_pos < 0)
|
||||
if ((filebuffer_pos+ctx->startbytes_pos) < 0)
|
||||
{
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
|
||||
}
|
||||
|
||||
@@ -538,6 +538,8 @@ void general_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
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;
|
||||
|
||||
@@ -50,6 +50,7 @@ struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
|
||||
|
||||
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.
|
||||
@@ -116,6 +117,8 @@ void dinit_libraries( struct lib_ccx_ctx **ctx)
|
||||
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);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CCX_CCEXTRACTOR_H
|
||||
#define CCX_CCEXTRACTOR_H
|
||||
|
||||
#define VERSION "0.75"
|
||||
#define VERSION "0.76"
|
||||
|
||||
// Load common includes and constants for library usage
|
||||
#include "ccx_common_platform.h"
|
||||
@@ -56,6 +56,49 @@ struct PMT_entry
|
||||
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
|
||||
@@ -135,6 +178,7 @@ struct lib_ccx_ctx
|
||||
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
|
||||
@@ -172,6 +216,14 @@ struct lib_ccx_ctx
|
||||
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;
|
||||
@@ -311,6 +363,8 @@ 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);
|
||||
|
||||
@@ -905,7 +905,7 @@ int start_upd_srv(const char *addr_str, unsigned port)
|
||||
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"bind() eror: %ld\n", WSAGetLastError());
|
||||
wprintf(L"bind() error: %ld\n", WSAGetLastError());
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "bind() error: %s\n", strerror(errno));
|
||||
|
||||
@@ -110,6 +110,8 @@ void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int lengt
|
||||
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 */
|
||||
|
||||
@@ -129,7 +129,7 @@ int parsedelay (struct ccx_s_options *opt, char *par)
|
||||
c++;
|
||||
}
|
||||
if (sign)
|
||||
opt->subs_delay =- opt->subs_delay;
|
||||
opt->subs_delay = -opt->subs_delay;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -272,8 +272,16 @@ void set_input_format (struct ccx_s_options *opt, const char *format)
|
||||
format++;
|
||||
if (strcmp (format,"es")==0) // Does this actually do anything?
|
||||
opt->auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
else if (strcmp (format,"ts")==0)
|
||||
else if (strcmp(format, "ts") == 0)
|
||||
{
|
||||
opt->auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->m2ts = 0;
|
||||
}
|
||||
else if (strcmp(format, "m2ts") == 0)
|
||||
{
|
||||
opt->auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->m2ts = 1;
|
||||
}
|
||||
else if (strcmp (format,"ps")==0 || strcmp (format,"nots")==0)
|
||||
opt->auto_stream = CCX_SM_PROGRAM;
|
||||
else if (strcmp (format,"asf")==0 || strcmp (format,"dvr-ms")==0)
|
||||
@@ -525,6 +533,8 @@ void usage (void)
|
||||
mprint (" -autodash: Based on position on screen, attempt to determine\n");
|
||||
mprint (" the different speakers and a dash (-) when each\n");
|
||||
mprint (" of them talks (.srt only, -trim required).");
|
||||
mprint (" -xmltv: produce an XMLTV file containing the EPG data from\n");
|
||||
mprint (" the source TS file.");
|
||||
|
||||
mprint ("Options that affect how ccextractor reads and writes (buffering):\n");
|
||||
|
||||
@@ -1465,6 +1475,51 @@ void parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
ccx_options.autodash = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-xmltv")==0)
|
||||
{
|
||||
if (i==argc-1 // Means no following argument
|
||||
|| !isanumber (argv[i+1])) // Means is not a number
|
||||
ccx_options.xmltv = 1;
|
||||
else
|
||||
{
|
||||
ccx_options.xmltv=atoi_hex (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp (argv[i],"-xmltvliveinterval")==0)
|
||||
{
|
||||
if (i==argc-1 // Means no following argument
|
||||
|| !isanumber (argv[i+1])) // Means is not a number
|
||||
ccx_options.xmltvliveinterval = 10;
|
||||
else
|
||||
{
|
||||
ccx_options.xmltvliveinterval=atoi_hex (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp (argv[i],"-xmltvoutputinterval")==0)
|
||||
{
|
||||
if (i==argc-1 // Means no following argument
|
||||
|| !isanumber (argv[i+1])) // Means is not a number
|
||||
ccx_options.xmltvoutputinterval = 0;
|
||||
else
|
||||
{
|
||||
ccx_options.xmltvoutputinterval=atoi_hex (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-xmltvonlycurrent")==0)
|
||||
{
|
||||
ccx_options.xmltvonlycurrent=1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp (argv[i],"-unixts")==0 && i<argc-1)
|
||||
{
|
||||
uint64_t t = 0;
|
||||
|
||||
@@ -73,9 +73,26 @@ void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
// Eight sync bytes, that's good enough
|
||||
ctx->startbytes_pos=i;
|
||||
ctx->stream_mode=CCX_SM_TRANSPORT;
|
||||
ctx->m2ts = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check for M2TS
|
||||
for (unsigned i = 0; i<192; i++)
|
||||
{
|
||||
if (ctx->startbytes[i+4] == 0x47 && ctx->startbytes[i + 4 + 192] == 0x47 &&
|
||||
ctx->startbytes[i + 192 * 2+4] == 0x47 && ctx->startbytes[i + 192 * 3+4] == 0x47 &&
|
||||
ctx->startbytes[i + 192 * 4+4] == 0x47 && ctx->startbytes[i + 192 * 5+4] == 0x47 &&
|
||||
ctx->startbytes[i + 192 * 6+4] == 0x47 && ctx->startbytes[i + 192 * 7+4] == 0x47
|
||||
)
|
||||
{
|
||||
// Eight sync bytes, that's good enough
|
||||
ctx->startbytes_pos = i;
|
||||
ctx->stream_mode = CCX_SM_TRANSPORT;
|
||||
ctx->m2ts = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now check for PS (Needs PACK header)
|
||||
for (unsigned i=0;
|
||||
i < (unsigned) (ctx->startbytes_avail<50000?ctx->startbytes_avail-3:49997);
|
||||
|
||||
@@ -503,7 +503,7 @@ void process_page(struct lib_ccx_ctx *ctx, teletext_page_t *page) {
|
||||
page_buffer_add_string("<br/>");
|
||||
break;
|
||||
default:
|
||||
page_buffer_add_string(encoded_crlf);
|
||||
page_buffer_add_string((const char *) encoded_crlf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,8 +656,8 @@ void process_page(struct lib_ccx_ctx *ctx, teletext_page_t *page) {
|
||||
}
|
||||
break;
|
||||
default: // Yes, this means everything else is .srt for now
|
||||
page_buffer_add_string (encoded_crlf);
|
||||
page_buffer_add_string (encoded_crlf);
|
||||
page_buffer_add_string ((const char *) encoded_crlf);
|
||||
page_buffer_add_string((const char *) encoded_crlf);
|
||||
if (ctx->wbout1.fh!=-1) {
|
||||
fdprintf(ctx->wbout1.fh,"%"PRIu32"%s%s --> %s%s", tlt_frames_produced, encoded_crlf, timecode_show, timecode_hide, encoded_crlf);
|
||||
fdprintf(ctx->wbout1.fh, "%s",page_buffer_cur);
|
||||
|
||||
@@ -57,6 +57,25 @@ void init_ts(struct lib_ccx_ctx *ctx)
|
||||
// Return 1 for sucessfully read ts packet
|
||||
int ts_readpacket(struct lib_ccx_ctx* ctx)
|
||||
{
|
||||
if (ctx->m2ts)
|
||||
{
|
||||
/* M2TS just adds 4 bytes to each packet (so size goes from 188 to 192)
|
||||
The 4 bytes are not important to us, so just skip
|
||||
// TP_extra_header {
|
||||
Copy_permission_indicator 2 unimsbf
|
||||
Arrival_time_stamp 30 unimsbf
|
||||
} */
|
||||
char tp_extra_header[4];
|
||||
buffered_read(ctx, tp_extra_header, 4);
|
||||
ctx->past += result;
|
||||
if (result != 4)
|
||||
{
|
||||
if (result>0)
|
||||
mprint("Premature end of file!\n");
|
||||
end_of_file = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
buffered_read(ctx, tspacket, 188);
|
||||
ctx->past+=result;
|
||||
if (result!=188)
|
||||
@@ -261,6 +280,11 @@ long ts_readstream(struct lib_ccx_ctx *ctx)
|
||||
ctx->capbuflen = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ccx_options.xmltv>=1 && payload.pid == 0x12) // This is DVB EIT
|
||||
parse_EPG_packet(ctx);
|
||||
if( ccx_options.xmltv>=1 && payload.pid >= 0x1000) // This may be ATSC EPG packet
|
||||
parse_EPG_packet(ctx);
|
||||
|
||||
// PID != 0 but no PMT selected yet, ignore the rest of the current
|
||||
// package and continue searching, UNLESS we are in -autoprogram, which requires us
|
||||
|
||||
@@ -600,7 +600,18 @@ int parse_PAT (struct lib_ccx_ctx *ctx)
|
||||
if (!ccx_options.ts_forced_program_selected)
|
||||
{
|
||||
if (!ccx_options.ts_autoprogram)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Run ccextractor again with --program-number specifying which program\nto process.");
|
||||
{
|
||||
if (ccx_options.xmltv >= 1)
|
||||
{
|
||||
mprint("Processing EPG only. If you want to extract subtitles use --program-number to select a program.");
|
||||
ccx_options.ts_forced_program_selected = 1;
|
||||
warning_program_not_found_shown = 1;
|
||||
ccx_options.write_format = CCX_OF_NULL;
|
||||
}
|
||||
else
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Run ccextractor again with --program-number specifying which program\nto process.");
|
||||
}
|
||||
|
||||
else
|
||||
mprint ("\nThe first program with a suitable CC stream will be selected.\n");
|
||||
}
|
||||
|
||||
896
src/lib_ccx/ts_tables_epg.c
Normal file
896
src/lib_ccx/ts_tables_epg.c
Normal file
@@ -0,0 +1,896 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
#include "utility.h"
|
||||
#include <stdbool.h>
|
||||
#ifdef WIN32
|
||||
#include "..\\win_iconv\\win_iconv.h"
|
||||
#else
|
||||
#include "iconv.h"
|
||||
#endif
|
||||
|
||||
//Prints a string to a file pointer, escaping XML special chars
|
||||
//Works with UTF-8
|
||||
void EPG_fprintxml(FILE *f, char *string) {
|
||||
char *p = string;
|
||||
char *start = p;
|
||||
while(*p!='\0') {
|
||||
switch(*p) {
|
||||
case '<':
|
||||
fwrite(start, 1, p-start, f);
|
||||
fprintf(f, "<");
|
||||
start = p+1;
|
||||
break;
|
||||
case '>':
|
||||
fwrite(start, 1, p-start, f);
|
||||
fprintf(f, ">");
|
||||
start = p+1;
|
||||
break;
|
||||
case '"':
|
||||
fwrite(start, 1, p-start, f);
|
||||
fprintf(f, """);
|
||||
start = p+1;
|
||||
break;
|
||||
case '&':
|
||||
fwrite(start, 1, p-start, f);
|
||||
fprintf(f, "&");
|
||||
start = p+1;
|
||||
break;
|
||||
case '\'':
|
||||
fwrite(start, 1, p-start, f);
|
||||
fprintf(f, "'");
|
||||
start = p+1;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
fwrite(start, 1, p-start, f);
|
||||
}
|
||||
|
||||
// Fills given string with given (event.*_time_string) ATSC time converted to XMLTV style time string
|
||||
void EPG_ATSC_calc_time(char *output, uint32_t time) {
|
||||
struct tm timeinfo;
|
||||
timeinfo.tm_year = 1980-1900;
|
||||
timeinfo.tm_mon = 0;
|
||||
timeinfo.tm_mday = 6;
|
||||
timeinfo.tm_sec = 0+time;
|
||||
timeinfo.tm_min = 0;
|
||||
timeinfo.tm_hour = 0;
|
||||
timeinfo.tm_isdst = -1;
|
||||
mktime(&timeinfo);
|
||||
sprintf(output, "%02d%02d%02d%02d%02d%02d +0000", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
}
|
||||
|
||||
// Fills event.start_time_string in XMLTV format with passed DVB time
|
||||
void EPG_DVB_calc_start_time(struct EPG_event *event, uint64_t time) {
|
||||
uint64_t mjd = time>>24;
|
||||
event->start_time_string[0]='\0';
|
||||
if (mjd > 0) {
|
||||
long y,m,d ,k;
|
||||
|
||||
// algo: ETSI EN 300 468 - ANNEX C
|
||||
y = (long) ((mjd - 15078.2) / 365.25);
|
||||
m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
|
||||
d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
|
||||
k = (m == 14 || m == 15) ? 1 : 0;
|
||||
y = y + k + 1900;
|
||||
m = m - 1 - k*12;
|
||||
|
||||
sprintf(event->start_time_string, "%02d%02d%02d%06x +0000",y,m,d,time&0xffffff);
|
||||
}
|
||||
}
|
||||
|
||||
// Fills event.end_time_string in XMLTV with passed DVB time + duration
|
||||
void EPG_DVB_calc_end_time(struct EPG_event *event, uint64_t time, uint32_t duration) {
|
||||
uint64_t mjd = time>>24;
|
||||
event->end_time_string[0]='\0';
|
||||
if (mjd > 0) {
|
||||
long y,m,d ,k;
|
||||
struct tm timeinfo;
|
||||
|
||||
// algo: ETSI EN 300 468 - ANNEX C
|
||||
y = (long) ((mjd - 15078.2) / 365.25);
|
||||
m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
|
||||
d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
|
||||
k = (m == 14 || m == 15) ? 1 : 0;
|
||||
y = y + k + 1900;
|
||||
m = m - 1 - k*12;
|
||||
|
||||
timeinfo.tm_year = y-1900;
|
||||
timeinfo.tm_mon = m-1;
|
||||
timeinfo.tm_mday = d;
|
||||
|
||||
timeinfo.tm_sec = (time&0x0f) + (10*((time&0xf0)>>4)) + (duration&0x0f) + (10*((duration&0xf0)>>4));
|
||||
timeinfo.tm_min = ((time&0x0f00)>>8) + (10*((time&0xf000)>>4)>>8) + ((duration&0x0f00)>>8) + (10*((duration&0xf000)>>4)>>8);
|
||||
timeinfo.tm_hour = ((time&0x0f0000)>>16) + (10*((time&0xf00000)>>4)>>16) + ((duration&0x0f0000)>>16) + (10*((duration&0xf00000)>>4)>>16);
|
||||
timeinfo.tm_isdst = -1;
|
||||
mktime(&timeinfo);
|
||||
sprintf(event->end_time_string, "%02d%02d%02d%02d%02d%02d +0000", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
}
|
||||
}
|
||||
|
||||
// returns english string description of the passed DVB category ID
|
||||
char *EPG_DVB_content_type_to_string(uint8_t cat) {
|
||||
struct table {
|
||||
uint8_t cat;
|
||||
char *name;
|
||||
};
|
||||
struct table t[] = {
|
||||
{0x00, "reserved"}, { 0x10, "movie/drama (general)" }, { 0x11, "detective/thriller" }, { 0x12, "adventure/western/war" }, { 0x13, "science fiction/fantasy/horror" },{ 0x14, "comedy" },
|
||||
{ 0x15, "soap/melodram/folkloric" }, { 0x16, "romance" }, { 0x17, "serious/classical/religious/historical movie/drama" }, { 0x18, "adult movie/drama" }, { 0x1E, "reserved" },
|
||||
{ 0x1F, "user defined" }, { 0x20, "news/current affairs (general)" }, { 0x21, "news/weather report" }, { 0x22, "news magazine" }, { 0x23, "documentary" }, { 0x24, "discussion/interview/debate" },
|
||||
{ 0x2E, "reserved" }, { 0x2F, "user defined" }, { 0x30, "show/game show (general)" }, { 0x31, "game show/quiz/contest" }, { 0x32, "variety show" }, { 0x33, "talk show" }, { 0x3E, "reserved" },
|
||||
{ 0x3F, "user defined" }, { 0x40, "sports (general)" }, { 0x41, "special events" }, { 0x42, "sports magazine" }, { 0x43, "football/soccer" }, { 0x44, "tennis/squash" }, { 0x45, "team sports" },
|
||||
{ 0x46, "athletics" }, { 0x47, "motor sport" }, { 0x48, "water sport" }, { 0x49, "winter sport" }, { 0x4A, "equestrian" }, { 0x4B, "martial sports" }, { 0x4E, "reserved" }, { 0x4F, "user defined" },
|
||||
{ 0x50, "childrens's/youth program (general)" }, { 0x51, "pre-school children's program" }, { 0x52, "entertainment (6-14 year old)" }, { 0x53, "entertainment (10-16 year old)" },
|
||||
{ 0x54, "information/education/school program" }, { 0x55, "cartoon/puppets" }, { 0x5E, "reserved" }, { 0x5F, "user defined" }, { 0x60, "music/ballet/dance (general)" }, { 0x61, "rock/pop" },
|
||||
{ 0x62, "serious music/classic music" }, { 0x63, "folk/traditional music" }, { 0x64, "jazz" }, { 0x65, "musical/opera" }, { 0x66, "ballet" }, { 0x6E, "reserved" }, { 0x6F, "user defined" },
|
||||
{ 0x70, "arts/culture (without music, general)" },{ 0x71, "performing arts" }, { 0x72, "fine arts" }, { 0x73, "religion" }, { 0x74, "popular culture/traditional arts" }, { 0x75, "literature" },
|
||||
{ 0x76, "film/cinema" }, { 0x77, "experimental film/video" }, { 0x78, "broadcasting/press" }, { 0x79, "new media" }, { 0x7A, "arts/culture magazine" }, { 0x7B, "fashion" }, { 0x7E, "reserved" },
|
||||
{ 0x7F, "user defined" }, { 0x80, "social/political issues/economics (general)" }, { 0x81, "magazines/reports/documentary" }, { 0x82, "economics/social advisory" }, { 0x83, "remarkable people" },
|
||||
{ 0x8E, "reserved" }, { 0x8F, "user defined" }, { 0x90, "education/science/factual topics (general)" }, { 0x91, "nature/animals/environment" }, { 0x92, "technology/natural science" },
|
||||
{ 0x93, "medicine/physiology/psychology" }, { 0x94, "foreign countries/expeditions" }, { 0x95, "social/spiritual science" }, { 0x96, "further education" }, { 0x97, "languages" },
|
||||
{ 0x9E, "reserved" }, { 0x9F, "user defined" }, { 0xA0, "leisure hobbies (general)" }, { 0xA1, "tourism/travel" }, { 0xA2, "handicraft" }, { 0xA3, "motoring" }, { 0xA4, "fitness & health" },
|
||||
{ 0xA5, "cooking" }, { 0xA6, "advertisement/shopping" }, { 0xA7, "gardening" }, { 0xAE, "reserved" }, { 0xAF, "user defined" }, { 0xB0, "original language" }, { 0xB1, "black & white" },
|
||||
{ 0xB2, "unpublished" }, { 0xB3, "live broadcast" }, { 0xBE, "reserved" }, { 0xBF, "user defined" }, { 0xEF, "reserved" }, { 0xFF, "user defined" }, {0x00, NULL},
|
||||
};
|
||||
struct table *p = t;
|
||||
while(p->name!=NULL) {
|
||||
if(cat==p->cat)
|
||||
return p->name;
|
||||
p++;
|
||||
}
|
||||
return "undefined content";
|
||||
|
||||
}
|
||||
|
||||
// Prints given event to already opened XMLTV file.
|
||||
void EPG_print_event(struct EPG_event *event, uint32_t channel, FILE *f) {
|
||||
int i;
|
||||
fprintf(f, " <program ");
|
||||
fprintf(f, "start=\"");
|
||||
fprintf(f, "%s", event->start_time_string);
|
||||
fprintf(f, "\" ");
|
||||
fprintf(f, "stop=\"");
|
||||
fprintf(f, "%s", event->end_time_string);
|
||||
fprintf(f, "\" ");
|
||||
fprintf(f, "channel=\"%i\">\n", channel);
|
||||
if(event->has_simple) {
|
||||
fprintf(f, " <title lang=\"%s\">", event->ISO_639_language_code);
|
||||
EPG_fprintxml(f, event->event_name);
|
||||
fprintf(f, "</title>\n");
|
||||
fprintf(f, " <sub-title lang=\"%s\">", event->ISO_639_language_code);
|
||||
EPG_fprintxml(f, event->text);
|
||||
fprintf(f, "</sub-title>\n");
|
||||
}
|
||||
if(event->extended_text!=NULL) {
|
||||
fprintf(f, " <desc lang=\"%s\">", event->extended_ISO_639_language_code);
|
||||
EPG_fprintxml(f, event->extended_text);
|
||||
fprintf(f, "</desc>\n");
|
||||
}
|
||||
for(i=0; i<event->num_ratings; i++)
|
||||
if(event->ratings[i].age>0 && event->ratings[i].age<0x10)
|
||||
fprintf(f, " <rating system=\"dvb:%s\">%i</rating>\n", event->ratings[i].country_code, event->ratings[i].age+3);
|
||||
for(i=0; i<event->num_categories; i++) {
|
||||
fprintf(f, " <category lang=\"en\">");
|
||||
EPG_fprintxml(f, EPG_DVB_content_type_to_string(event->categories[i]));
|
||||
fprintf(f, "</category>\n");
|
||||
}
|
||||
fprintf(f, " <ts-meta-id>%i</ts-meta-id>\n", event->id);
|
||||
fprintf(f, " </program>\n");
|
||||
}
|
||||
|
||||
// Creates fills and closes a new XMLTV file for live mode output.
|
||||
// File should include only events not previously output.
|
||||
void EPG_output_live(struct lib_ccx_ctx *ctx) {
|
||||
int c=false, i, j;
|
||||
FILE *f;
|
||||
char *filename, *finalfilename;
|
||||
for(i=0; i<pmt_array_length; i++) {
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
if(ctx->eit_programs[i].epg_events[j].live_output==false) {
|
||||
c=true;
|
||||
}
|
||||
}
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
filename = malloc(strlen(ctx->basefilename)+30);
|
||||
sprintf(filename, "%s_%i.xml.part", ctx->basefilename, ctx->epg_last_live_output);
|
||||
f = fopen(filename, "w");
|
||||
|
||||
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
|
||||
for(i=0; i<pmt_array_length; i++) {
|
||||
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
|
||||
fprintf(f, " </channel>\n");
|
||||
}
|
||||
for(i=0; i<pmt_array_length; i++) {
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
if(ctx->eit_programs[i].epg_events[j].live_output==false) {
|
||||
ctx->eit_programs[i].epg_events[j].live_output=true;
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
|
||||
}
|
||||
}
|
||||
fprintf(f, "</tv>");
|
||||
fclose(f);
|
||||
finalfilename = malloc(strlen(ctx->wbout1.filename)+30);
|
||||
memcpy(finalfilename, filename, strlen(filename)-5);
|
||||
finalfilename[strlen(filename)-5]='\0';
|
||||
rename(filename, finalfilename);
|
||||
free(filename);
|
||||
free(finalfilename);
|
||||
}
|
||||
|
||||
// Creates fills and closes a new XMLTV file for full output mode.
|
||||
// File should include all events in memory.
|
||||
void EPG_output(struct lib_ccx_ctx *ctx) {
|
||||
FILE *f;
|
||||
char *filename;
|
||||
int i,j, ce;
|
||||
filename = malloc(strlen(ctx->basefilename) + 9);
|
||||
memcpy(filename, ctx->basefilename, strlen(ctx->basefilename)+1);
|
||||
strcat(filename, "_epg.xml");
|
||||
f = fopen(filename, "w");
|
||||
free(filename);
|
||||
fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
|
||||
for(i=0; i<pmt_array_length; i++) {
|
||||
fprintf(f, " <channel id=\"%i\">\n", pmt_array[i].program_number);
|
||||
fprintf(f, " <display-name>%i</display-name>\n", pmt_array[i].program_number);
|
||||
fprintf(f, " </channel>\n");
|
||||
}
|
||||
if(ccx_options.xmltvonlycurrent==0) { // print all events
|
||||
for(i=0; i<pmt_array_length; i++) {
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++)
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
|
||||
}
|
||||
|
||||
if(pmt_array_length==0) //Stream has no PMT, fall back to unordered events
|
||||
for(j=0; j<ctx->eit_programs[TS_PMT_MAP_SIZE].array_len; j++)
|
||||
EPG_print_event(&ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j], ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j].service_id, f);
|
||||
}
|
||||
else { // print current events only
|
||||
for(i=0; i<pmt_array_length; i++) {
|
||||
ce = ctx->eit_current_events[i];
|
||||
for(j=0; j<ctx->eit_programs[i].array_len; j++) {
|
||||
if(ce==ctx->eit_programs[i].epg_events[j].id)
|
||||
EPG_print_event(&ctx->eit_programs[i].epg_events[j], pmt_array[i].program_number, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "</tv>");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
// Free all memory allocated for given event
|
||||
void EPG_free_event(struct EPG_event *event) {
|
||||
if(event->has_simple) {
|
||||
free(event->event_name);
|
||||
free(event->text);
|
||||
}
|
||||
if(event->extended_text!=NULL)
|
||||
free(event->extended_text);
|
||||
if(event->num_ratings>0)
|
||||
free(event->ratings);
|
||||
if(event->num_categories>0)
|
||||
free(event->categories);
|
||||
}
|
||||
|
||||
//compare 2 events. Return false if they are different.
|
||||
int EPG_event_cmp(struct EPG_event *e1, struct EPG_event *e2) {
|
||||
if(e1->id != e2->id || (strcmp(e1->start_time_string, e2->start_time_string)!=0) || (strcmp(e1->end_time_string, e2->end_time_string)!=0))
|
||||
return false;
|
||||
// could add full checking of strings here if desired.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add given event to array of events.
|
||||
// Return FALSE if nothing changed, TRUE if this is a new or updated event.
|
||||
int EPG_add_event(struct lib_ccx_ctx *ctx, int32_t pmt_map, struct EPG_event *event) {
|
||||
int isnew=true, j;
|
||||
|
||||
for(j=0; j<ctx->eit_programs[pmt_map].array_len; j++) {
|
||||
if(ctx->eit_programs[pmt_map].epg_events[j].id==event->id) {
|
||||
if(EPG_event_cmp(event, &ctx->eit_programs[pmt_map].epg_events[j]))
|
||||
return false; //event already in array, nothing to do
|
||||
else { //event with this id is already in the array but something has changed. Update it.
|
||||
event->count=ctx->eit_programs[pmt_map].epg_events[j].count;
|
||||
EPG_free_event(&ctx->eit_programs[pmt_map].epg_events[j]);
|
||||
memcpy(&ctx->eit_programs[pmt_map].epg_events[j], event, sizeof(struct EPG_event));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// id not in array. Add new event;
|
||||
event->count=0;
|
||||
memcpy(&ctx->eit_programs[pmt_map].epg_events[ctx->eit_programs[pmt_map].array_len], event, sizeof(struct EPG_event));
|
||||
ctx->eit_programs[pmt_map].array_len++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//EN 300 468 V1.3.1 (1998-02)
|
||||
//6.2.4 Content descriptor
|
||||
void EPG_decode_content_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event) {
|
||||
int i;
|
||||
int num_items = descriptor_length/2;
|
||||
if(num_items == 0) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT content_descriptor length detected.\n");
|
||||
return;
|
||||
}
|
||||
event->categories = malloc(1*num_items);
|
||||
event->num_categories = num_items;
|
||||
for(i=0; i<num_items; i++) {
|
||||
event->categories[i] = offset[0];
|
||||
offset+=2;
|
||||
}
|
||||
}
|
||||
|
||||
//EN 300 468 V1.3.1 (1998-02)
|
||||
//6.2.20 Parental rating descripto
|
||||
void EPG_decode_parental_rating_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event) {
|
||||
int i;
|
||||
int num_items = descriptor_length/4;
|
||||
struct EPG_rating *ratings;
|
||||
|
||||
if(num_items == 0) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT parental_rating length detected.\n");
|
||||
return;
|
||||
}
|
||||
event->ratings = malloc(sizeof(struct EPG_rating)*num_items);
|
||||
|
||||
ratings = event->ratings;
|
||||
event->num_ratings = num_items;
|
||||
for(i=0; i<descriptor_length/4; i++) {
|
||||
ratings[i].country_code[0] = offset[0];
|
||||
ratings[i].country_code[1] = offset[1];
|
||||
ratings[i].country_code[2] = offset[2];
|
||||
ratings[i].country_code[3] = '\0';
|
||||
if(offset[3] == 0x00 || offset[3] >=0x10)
|
||||
ratings[i].age = 0;
|
||||
else
|
||||
ratings[i].age = offset[3];
|
||||
offset+=4;
|
||||
}
|
||||
}
|
||||
|
||||
// an ungly function to convert from dvb codepages to UTF-8859-9 using iconv
|
||||
// returns a null terminated UTF8-strings
|
||||
// EN 300 468 V1.7.1 (2006-05)
|
||||
// A.2 Selection of Character table
|
||||
char* EPG_DVB_decode_string(uint8_t *in, size_t size) {
|
||||
uint8_t *out;
|
||||
uint16_t decode_buffer_size = (size*4)+1;
|
||||
uint8_t *decode_buffer = malloc(decode_buffer_size);
|
||||
char *dp = &decode_buffer[0];
|
||||
size_t obl=decode_buffer_size;
|
||||
uint16_t osize=0;
|
||||
iconv_t cd=(iconv_t)(-1);
|
||||
int skipiconv = false;
|
||||
int ret=-1;
|
||||
int x;
|
||||
if(size==0) { // 0 length strings are valid
|
||||
decode_buffer[0]='\0';
|
||||
return decode_buffer;
|
||||
}
|
||||
|
||||
if(in[0]>=0x20) {
|
||||
skipiconv=true;
|
||||
}
|
||||
else if(in[0]==0x01) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-5"); //tested
|
||||
}
|
||||
else if(in[0]==0x02) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-6");
|
||||
}
|
||||
else if(in[0]==0x03) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-7");
|
||||
}
|
||||
else if(in[0]==0x04) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-8");
|
||||
}
|
||||
else if(in[0]==0x05) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-9");
|
||||
}
|
||||
else if(in[0]==0x06) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-10");
|
||||
}
|
||||
else if(in[0]==0x07) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-11");
|
||||
}
|
||||
else if(in[0]==0x08) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-12"); //This doesn't even exist?
|
||||
}
|
||||
else if(in[0]==0x09) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-13");
|
||||
}
|
||||
else if(in[0]==0x0a) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-14");
|
||||
}
|
||||
else if(in[0]==0x0b) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-15"); //tested, german
|
||||
}
|
||||
else if(in[0]==0x10) {
|
||||
char from[14];
|
||||
uint16_t cpn = (in[1] << 8) | in[2];
|
||||
size-=3; in+=3;
|
||||
snprintf(from, sizeof(from), "ISO8859-%d", cpn);
|
||||
cd = iconv_open("UTF-8", from);
|
||||
}
|
||||
else if(in[0]==0x11) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO-10646/UTF8");
|
||||
}
|
||||
else if(in[0]==0x12) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "KS_C_5601-1987");
|
||||
}
|
||||
else if(in[0]==0x13) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "GB2312");
|
||||
}
|
||||
else if(in[0]==0x14) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "BIG-5");
|
||||
}
|
||||
else if(in[0]==0x15) {
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "UTF-8");
|
||||
}
|
||||
else {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: EPG_DVB_decode_string(): Reserved encoding detected: %02x.\n", in[0]);
|
||||
size--; in++;
|
||||
cd = iconv_open("UTF-8", "ISO8859-9");
|
||||
}
|
||||
|
||||
if((long)cd != -1 && !skipiconv) {
|
||||
ret = iconv(cd, (char **)&in, &size, &dp, &obl);
|
||||
obl=decode_buffer_size-obl;
|
||||
decode_buffer[obl]=0x00;
|
||||
}
|
||||
else {
|
||||
uint16_t newsize=0;
|
||||
if(!skipiconv)
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: EPG_DVB_decode_string(): Failed to convert codepage.\n");
|
||||
/*
|
||||
http://dvbstreamer.sourcearchive.com/documentation/2.1.0-2/dvbtext_8c_source.html
|
||||
libiconv doesn't support ISO 6937, but glibc does?!
|
||||
so fall back to ISO8859-1 and strip out the non spacing
|
||||
diacritical mark/graphical characters etc.
|
||||
ALSO: http://lists.gnu.org/archive/html/bug-gnu-libiconv/2009-09/msg00000.html
|
||||
*/
|
||||
for(x=0; x<size; x++) {
|
||||
if(in[x]<=(uint8_t)127) {
|
||||
decode_buffer[newsize]=in[x];
|
||||
newsize++;
|
||||
}
|
||||
}
|
||||
size=newsize;
|
||||
decode_buffer[size]=0x00;
|
||||
}
|
||||
osize=strlen(decode_buffer);
|
||||
out = malloc(osize+1);
|
||||
memcpy(out, decode_buffer, osize);
|
||||
out[osize]=0x00;
|
||||
free(decode_buffer);
|
||||
if (cd != (iconv_t)-1)
|
||||
iconv_close(cd);
|
||||
return out;
|
||||
}
|
||||
|
||||
//EN 300 468 V1.3.1 (1998-02)
|
||||
//6.2.27 Short event descriptor
|
||||
void EPG_decode_short_event_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event) {
|
||||
uint8_t text_length;
|
||||
uint8_t event_name_length;
|
||||
event->has_simple=true;
|
||||
event->ISO_639_language_code[0] = offset[0];
|
||||
event->ISO_639_language_code[1] = offset[1];
|
||||
event->ISO_639_language_code[2] = offset[2];
|
||||
event->ISO_639_language_code[3] = 0x00;
|
||||
|
||||
event_name_length = offset[3];
|
||||
if(event_name_length+4>descriptor_length) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid short_event_descriptor size detected.\n");
|
||||
return;
|
||||
}
|
||||
event->event_name = EPG_DVB_decode_string(&offset[4], event_name_length);
|
||||
|
||||
text_length = offset[4+event_name_length];
|
||||
if(text_length+event_name_length+4>descriptor_length) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid short_event_descriptor size detected.\n");
|
||||
return;
|
||||
}
|
||||
event->text = EPG_DVB_decode_string(&offset[5+event_name_length], text_length);
|
||||
|
||||
}
|
||||
|
||||
//EN 300 468 V1.3.1 (1998-02)
|
||||
//6.2.9 Extended event descriptor
|
||||
void EPG_decode_extended_event_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event) {
|
||||
uint8_t descriptor_number=offset[0]>>4;
|
||||
uint8_t last_descriptor_number=(offset[0]&0x0f);
|
||||
uint32_t text_length;
|
||||
uint32_t oldlen=0;
|
||||
uint8_t length_of_items = offset[4];
|
||||
event->extended_ISO_639_language_code[0] = offset[1];
|
||||
event->extended_ISO_639_language_code[1] = offset[2];
|
||||
event->extended_ISO_639_language_code[2] = offset[3];
|
||||
event->extended_ISO_639_language_code[3] = 0x00;
|
||||
|
||||
offset=offset+length_of_items+5;
|
||||
if(length_of_items>descriptor_length-5) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid extended_event_descriptor size detected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
text_length = offset[0];
|
||||
if(text_length>descriptor_length-5-length_of_items-1) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid extended_event_text_length size detected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: can this leak memory with a malformed descriptor?
|
||||
if(descriptor_number>0) {
|
||||
if(offset[1]<0x20) {
|
||||
offset++;
|
||||
text_length--;
|
||||
}
|
||||
uint8_t *net = malloc(strlen(event->extended_text)+text_length+1);
|
||||
oldlen=strlen(event->extended_text);
|
||||
memcpy(net, event->extended_text, strlen(event->extended_text));
|
||||
free(event->extended_text);
|
||||
event->extended_text=net;
|
||||
}
|
||||
else
|
||||
event->extended_text = malloc(text_length+1);
|
||||
|
||||
memcpy(&event->extended_text[oldlen], &offset[1], text_length);
|
||||
|
||||
event->extended_text[oldlen + text_length] = '\0';
|
||||
|
||||
if(descriptor_number==last_descriptor_number) {
|
||||
uint8_t *old = event->extended_text;
|
||||
event->extended_text = EPG_DVB_decode_string(event->extended_text, strlen(event->extended_text));
|
||||
free(old);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// decode an ATSC multiple_string
|
||||
// extremly basic implementation
|
||||
// only handles single segment, single language ANSI string!
|
||||
void EPG_ATSC_decode_multiple_string(uint8_t *offset, uint32_t length, struct EPG_event *event) {
|
||||
uint8_t number_strings = offset[0];
|
||||
int i, j;
|
||||
char ISO_639_language_code[4];
|
||||
offset++;
|
||||
for(i=0; i<number_strings; i++) {
|
||||
uint8_t number_segments = offset[3];
|
||||
ISO_639_language_code[0] = offset[0];
|
||||
ISO_639_language_code[1] = offset[1];
|
||||
ISO_639_language_code[2] = offset[2];
|
||||
ISO_639_language_code[3] = 0x00;
|
||||
offset+=4;
|
||||
for (j=0; j< number_segments; j++) {
|
||||
uint8_t compression_type = offset[0];
|
||||
uint8_t mode = offset[1];
|
||||
uint8_t number_bytes = offset[2];
|
||||
offset+=3;
|
||||
if(mode==0 && compression_type==0 && j==0) {
|
||||
event->has_simple=true;
|
||||
event->ISO_639_language_code[0]=ISO_639_language_code[0];
|
||||
event->ISO_639_language_code[1]=ISO_639_language_code[1];
|
||||
event->ISO_639_language_code[2]=ISO_639_language_code[2];
|
||||
event->ISO_639_language_code[3]=0x00;
|
||||
event->event_name = malloc(number_bytes+1);
|
||||
memcpy(event->event_name, &offset[0], number_bytes);
|
||||
event->event_name[number_bytes]='\0';
|
||||
event->text = malloc(number_bytes+1);
|
||||
memcpy(event->text, &offset[0], number_bytes);
|
||||
event->text[number_bytes]='\0';
|
||||
}
|
||||
else {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Unsupported ATSC multiple_string encoding detected!.\n");
|
||||
}
|
||||
offset+=number_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decode ATSC EIT table.
|
||||
void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size) {
|
||||
uint8_t table_id = payload_start[0];
|
||||
struct EPG_event event;
|
||||
uint8_t num_events_in_section;
|
||||
uint8_t *offset;
|
||||
int hasnew=false;
|
||||
int i, j;
|
||||
uint16_t source_id = ((payload_start[3]) << 8) | payload_start[4];
|
||||
int32_t pmt_map = -1;
|
||||
event.has_simple=false;
|
||||
event.extended_text=NULL;
|
||||
event.num_ratings=0;
|
||||
event.num_categories=0;
|
||||
event.live_output=false;
|
||||
for (i = 0; i < pmt_array_length; i++)
|
||||
{
|
||||
if (pmt_array[i].program_number == ctx->ATSC_source_pg_map[source_id])
|
||||
pmt_map=i;
|
||||
}
|
||||
|
||||
//Don't know how to stroe EPG until we know the programs. Ignore it.
|
||||
if(pmt_map==-1)
|
||||
pmt_map=TS_PMT_MAP_SIZE;
|
||||
|
||||
num_events_in_section = payload_start[9];
|
||||
offset=&payload_start[10];
|
||||
|
||||
for(j=0; j<num_events_in_section; j++) {
|
||||
uint16_t descriptors_loop_length;
|
||||
uint8_t title_length, emt_location;
|
||||
uint32_t length_in_seconds, start_time, full_id;
|
||||
uint16_t event_id = ((offset[0]&0x3F) << 8) | offset[1];
|
||||
full_id = (source_id << 16) | event_id;
|
||||
event.id=full_id;
|
||||
event.service_id=source_id;
|
||||
start_time = (offset[2] << 24) | (offset[3] << 16) | (offset[4] << 8)| (offset[5] << 0);
|
||||
EPG_ATSC_calc_time(event.start_time_string, start_time);
|
||||
emt_location = (offset[6]&0x30)>>4;
|
||||
length_in_seconds = (((offset[6]&0x0F) << 16) | (offset[7] << 8) | (offset[8] << 0));
|
||||
EPG_ATSC_calc_time(event.end_time_string, start_time+length_in_seconds);
|
||||
title_length = offset[9];
|
||||
EPG_ATSC_decode_multiple_string(&offset[10], title_length, &event);
|
||||
|
||||
descriptors_loop_length = ((offset[10+title_length] & 0x0f) << 8) | offset[10+title_length+1];
|
||||
|
||||
hasnew |= EPG_add_event(ctx, pmt_map, &event);
|
||||
offset+=12+descriptors_loop_length+title_length;
|
||||
}
|
||||
if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew)
|
||||
EPG_output(ctx);
|
||||
}
|
||||
|
||||
// decode ATSC VCT table.
|
||||
void EPG_ATSC_decode_VCT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size) {
|
||||
uint8_t table_id = payload_start[0];
|
||||
uint8_t num_channels_in_section = payload_start[9];
|
||||
uint8_t *offset = &payload_start[10];
|
||||
int i;
|
||||
for (i=0; i< num_channels_in_section; i++) {
|
||||
char short_name[7*2];
|
||||
uint16_t program_number = offset[24]<<8 | offset[25];
|
||||
uint16_t source_id = offset[28]<<8 | offset[29];
|
||||
uint16_t descriptors_loop_length = ((offset[30] & 0x03) << 8) | offset[31];
|
||||
memcpy(short_name, &offset[0], 7*2);
|
||||
offset+=32+descriptors_loop_length;
|
||||
ctx->ATSC_source_pg_map[source_id]=program_number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size) {
|
||||
|
||||
uint8_t table_id = payload_start[0];
|
||||
//uint8_t section_syntax_indicator = (0xf1&0x80)>>7;
|
||||
uint16_t section_length = (payload_start[1]&0x0F)<<8 | payload_start[2];
|
||||
uint16_t service_id = (payload_start[3] << 8) | payload_start[4];
|
||||
int32_t pmt_map = -1;
|
||||
int i;
|
||||
int hasnew=false;
|
||||
struct EPG_event event;
|
||||
uint8_t section_number = payload_start[6];
|
||||
uint8_t last_section_number = payload_start[7];
|
||||
uint8_t segment_last_section_number = payload_start[12];
|
||||
uint32_t events_length = section_length - 11;
|
||||
uint8_t *offset=payload_start;
|
||||
uint32_t remaining=events_length;
|
||||
for (i = 0; i < pmt_array_length; i++)
|
||||
{
|
||||
if (pmt_array[i].program_number == service_id)
|
||||
pmt_map=i;
|
||||
}
|
||||
|
||||
//For any service we don't have an PMT for (yet), store it in the special last array pos.
|
||||
if(pmt_map==-1)
|
||||
pmt_map=TS_PMT_MAP_SIZE;
|
||||
|
||||
if(events_length>size-14) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT packet size detected.\n");
|
||||
}
|
||||
|
||||
while(remaining>4) {
|
||||
uint16_t descriptors_loop_length;
|
||||
uint8_t *descp;
|
||||
uint32_t duration;
|
||||
uint64_t start_time;
|
||||
event.id=(offset[14] << 8) | offset[15];
|
||||
event.has_simple=false;
|
||||
event.extended_text=NULL;
|
||||
event.num_ratings=0;
|
||||
event.num_categories=0;
|
||||
event.live_output=false;
|
||||
event.service_id=service_id;
|
||||
|
||||
//40 bits
|
||||
start_time = ((uint64_t)offset[16] << 32) | ((uint64_t)offset[17] << 24) | ((uint64_t)offset[18] << 16) | ((uint64_t)offset[19] << 8)| ((uint64_t)offset[20] << 0);
|
||||
EPG_DVB_calc_start_time(&event, start_time);
|
||||
//24 bits
|
||||
duration = (offset[21] << 16 ) | (offset[22] << 8 ) | (offset[23] << 0 );
|
||||
EPG_DVB_calc_end_time(&event, start_time, duration);
|
||||
event.running_status = (offset[24] & 0xE0) >> 5;
|
||||
event.free_ca_mode = (offset[24] & 0x10) >> 4;
|
||||
//12 bits
|
||||
descriptors_loop_length = ((offset[24] & 0x0f) << 8) | offset[25];
|
||||
descp = &offset[26];
|
||||
if(descriptors_loop_length > remaining-16) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT descriptors_loop_length detected.\n");
|
||||
return;
|
||||
}
|
||||
while(descp<&(offset[26])+descriptors_loop_length) {
|
||||
if(descp+descp[1]+2>payload_start+size) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT descriptor_loop_length detected.\n");
|
||||
EPG_free_event(&event);
|
||||
return;
|
||||
}
|
||||
if(descp[0]==0x4d)
|
||||
EPG_decode_short_event_descriptor(descp+2, descp[1], &event);
|
||||
if(descp[0]==0x4e)
|
||||
EPG_decode_extended_event_descriptor(descp+2, descp[1], &event);
|
||||
if(descp[0]==0x54)
|
||||
EPG_decode_content_descriptor(descp+2, descp[1], &event);
|
||||
if(descp[0]==0x55)
|
||||
EPG_decode_parental_rating_descriptor(descp+2, descp[1], &event);
|
||||
if(descp[1]+2==0) {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT descriptor_length detected.\n");
|
||||
return;
|
||||
}
|
||||
descp=descp+(descp[1]+2);
|
||||
}
|
||||
remaining=remaining-(descriptors_loop_length+12);
|
||||
offset=offset+descriptors_loop_length+12;
|
||||
hasnew |= EPG_add_event(ctx, pmt_map, &event);
|
||||
|
||||
if(hasnew && section_number==0 && table_id==0x4e)
|
||||
ctx->eit_current_events[pmt_map]=event.id;
|
||||
}
|
||||
|
||||
if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew)
|
||||
EPG_output(ctx);
|
||||
|
||||
}
|
||||
//handle outputing to xml files
|
||||
void EPG_handle_output(struct lib_ccx_ctx *ctx) {
|
||||
int cur_sec = (int) ((ctx->global_timestamp-ctx->min_global_timestamp) / 1000);
|
||||
if(ccx_options.xmltv==1 || ccx_options.xmltv==3) { //full outout
|
||||
if(ccx_options.xmltvoutputinterval!=0 && cur_sec>ctx->epg_last_output+ccx_options.xmltvliveinterval) {
|
||||
ctx->epg_last_output=cur_sec;
|
||||
EPG_output(ctx);
|
||||
}
|
||||
}
|
||||
if(ccx_options.xmltv==2 || ccx_options.xmltv==3) { //live output
|
||||
if(cur_sec>ctx->epg_last_live_output+ccx_options.xmltvliveinterval) {
|
||||
ctx->epg_last_live_output=cur_sec;
|
||||
EPG_output_live(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//determin table type and call the correct function to handle it
|
||||
void EPG_parse_table(struct lib_ccx_ctx *ctx, uint8_t *b, uint32_t size) {
|
||||
uint8_t pointer_field=b[0];
|
||||
uint8_t *payload_start = &b[pointer_field + 1];
|
||||
uint8_t table_id = payload_start[0];
|
||||
|
||||
switch (table_id) {
|
||||
case 0x0cb:
|
||||
EPG_ATSC_decode_EIT(ctx, payload_start, size);
|
||||
break;
|
||||
case 0xc8:
|
||||
EPG_ATSC_decode_VCT(ctx, payload_start, size);
|
||||
break;
|
||||
default:
|
||||
if (table_id>=0x4e && table_id<=0x6f)
|
||||
EPG_DVB_decode_EIT(ctx, payload_start, size);
|
||||
break;
|
||||
}
|
||||
EPG_handle_output(ctx);
|
||||
}
|
||||
|
||||
// recounsructs DVB EIT and ATSC tables
|
||||
void parse_EPG_packet(struct lib_ccx_ctx *ctx) {
|
||||
unsigned char *payload_start = tspacket + 4;
|
||||
unsigned payload_length = 188 - 4;
|
||||
unsigned transport_error_indicator = (tspacket[1]&0x80)>>7;
|
||||
unsigned payload_start_indicator = (tspacket[1]&0x40)>>6;
|
||||
// unsigned transport_priority = (tspacket[1]&0x20)>>5;
|
||||
unsigned pid = (((tspacket[1] & 0x1F) << 8) | tspacket[2]) & 0x1FFF;
|
||||
// unsigned transport_scrambling_control = (tspacket[3]&0xC0)>>6;
|
||||
unsigned adaptation_field_control = (tspacket[3]&0x30)>>4;
|
||||
unsigned ccounter = tspacket[3] & 0xF;
|
||||
unsigned adaptation_field_length = 0;
|
||||
int buffer_map = 0xfff;
|
||||
if ( adaptation_field_control & 2 )
|
||||
{
|
||||
adaptation_field_length = tspacket[4];
|
||||
payload_start = payload_start + adaptation_field_length + 1;
|
||||
payload_length = tspacket+188-payload_start;
|
||||
}
|
||||
|
||||
if((pid!=0x12 && pid!=0x1ffb && pid<0x1000) || pid==0x1fff)
|
||||
return;
|
||||
|
||||
if(pid!=0x12)
|
||||
buffer_map = pid-0x1000;
|
||||
|
||||
if(payload_start_indicator) {
|
||||
if(ctx->epg_buffers[buffer_map].ccounter>0) {
|
||||
ctx->epg_buffers[buffer_map].ccounter=0;
|
||||
EPG_parse_table(ctx, ctx->epg_buffers[buffer_map].buffer, ctx->epg_buffers[buffer_map].buffer_length);
|
||||
}
|
||||
|
||||
|
||||
ctx->epg_buffers[buffer_map].prev_ccounter = ccounter;
|
||||
|
||||
if(ctx->epg_buffers[buffer_map].buffer!=NULL)
|
||||
free(ctx->epg_buffers[buffer_map].buffer);
|
||||
else {
|
||||
// must be first EIT packet
|
||||
}
|
||||
ctx->epg_buffers[buffer_map].buffer = (uint8_t *)malloc(payload_length);
|
||||
memcpy(ctx->epg_buffers[buffer_map].buffer, payload_start, payload_length);
|
||||
ctx->epg_buffers[buffer_map].buffer_length=payload_length;
|
||||
ctx->epg_buffers[buffer_map].ccounter++;
|
||||
|
||||
}
|
||||
else if(ccounter==ctx->epg_buffers[buffer_map].prev_ccounter+1 || (ctx->epg_buffers[buffer_map].prev_ccounter==0x0f && ccounter==0)) {
|
||||
ctx->epg_buffers[buffer_map].prev_ccounter = ccounter;
|
||||
ctx->epg_buffers[buffer_map].buffer = (uint8_t *)realloc(ctx->epg_buffers[buffer_map].buffer, ctx->epg_buffers[buffer_map].buffer_length+payload_length);
|
||||
memcpy(ctx->epg_buffers[buffer_map].buffer+ctx->epg_buffers[buffer_map].buffer_length, payload_start, payload_length);
|
||||
ctx->epg_buffers[buffer_map].ccounter++;
|
||||
ctx->epg_buffers[buffer_map].buffer_length+=payload_length;
|
||||
}
|
||||
else {
|
||||
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Out of order EPG packets detected.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Free all memory used for EPG parsing
|
||||
void EPG_free(struct lib_ccx_ctx *ctx) {
|
||||
int i = 0, j;
|
||||
if(ccx_options.xmltv==2 || ccx_options.xmltv==3) {
|
||||
EPG_output_live(ctx);
|
||||
}
|
||||
for (i = 0; i < TS_PMT_MAP_SIZE; i++)
|
||||
{
|
||||
for(j = 0; j < ctx->eit_programs[i].array_len; j++)
|
||||
{
|
||||
if(ctx->eit_programs[i].epg_events[j].has_simple) {
|
||||
free(ctx->eit_programs[i].epg_events[j].event_name);
|
||||
free(ctx->eit_programs[i].epg_events[j].text);
|
||||
}
|
||||
if(ctx->eit_programs[i].epg_events[j].extended_text!=NULL)
|
||||
free(ctx->eit_programs[i].epg_events[j].extended_text);
|
||||
if(ctx->eit_programs[i].epg_events[j].num_ratings>0)
|
||||
free(ctx->eit_programs[i].epg_events[j].ratings);
|
||||
if(ctx->eit_programs[i].epg_events[j].num_categories>0)
|
||||
free(ctx->eit_programs[i].epg_events[j].categories);
|
||||
}
|
||||
ctx->eit_programs[i].array_len=0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 0xfff; i++) {
|
||||
if(ctx->epg_buffers[i].buffer!=NULL)
|
||||
free(ctx->epg_buffers[i].buffer);
|
||||
}
|
||||
}
|
||||
2074
src/win_iconv/win_iconv.h
Normal file
2074
src/win_iconv/win_iconv.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $
|
||||
* $Id: dirent.h,v 1.1 2015/01/16 07:40:15 cfsmp3 Exp $
|
||||
*/
|
||||
#ifndef DIRENT_H
|
||||
#define DIRENT_H
|
||||
|
||||
@@ -173,6 +173,7 @@
|
||||
<ClCompile Include="..\src\lib_ccx\telxcc.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_functions.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_tables.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\ts_tables_epg.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\utility.c" />
|
||||
<ClCompile Include="..\src\lib_ccx\wtv_functions.c" />
|
||||
<ClCompile Include="..\src\zlib\adler32.c" />
|
||||
|
||||
Reference in New Issue
Block a user