Compare commits

...

111 Commits
v0.73 ... v0.75

Author SHA1 Message Date
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
117 changed files with 5371 additions and 4171 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.71
V = 0.75
DISTFILES = ccextractor.${V:S/.//}-src.zip
MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=ccextractor/}
DISTNAME = ccextractor-$V

View File

@@ -1,3 +1,22 @@
0.75
-----------
- 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
-----------
- 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
-----------
- Added support of BIN format for Teletext

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.73
ccextractor, 0.75
-----------------
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
Maintainer: cfsmp3

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

@@ -3,7 +3,7 @@ SHELL = /bin/sh
CC = gcc
SYS := $(shell gcc -dumpmachine)
CFLAGS = -O3 -std=gnu99
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib
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
@@ -13,12 +13,16 @@ 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)
@@ -38,10 +42,31 @@ 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)
@@ -59,8 +84,8 @@ all: objs_dir $(TARGET)
objs_dir:
mkdir -p $(OBJS_DIR)
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB)
$(CC) $(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 $@
@@ -71,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
@@ -85,7 +110,7 @@ uninstall:
.PHONY: depend dep
depend dep:
$(CC) $(CFLAGS) -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

View File

@@ -1 +1 @@
gcc -std=gnu99 -Wno-write-strings -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') $(find ../src/ -name '*.c')

View File

@@ -1,285 +0,0 @@
#include "ccextractor.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)
{
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
int x_pos, y_pos, width, height, i;
int x, y, y_off, x_off, ret;
uint8_t *pbuf;
//char *filename;
struct cc_bitmap* rect;
png_color *palette = NULL;
png_byte *alpha = NULL;
#ifdef ENABLE_OCR
char*str = NULL;
#endif
//int used;
#ifdef ENABLE_OCR
unsigned h1, m1, s1, ms1;
unsigned h2, m2, s2, ms2;
#endif
LLONG ms_start, ms_end;
//char timeline[128];
int len = 0;
x_pos = -1;
y_pos = -1;
width = 0;
height = 0;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + subs_delay;
ms_end = sub->start_time - 1;
}
else if ( !(sub->flags & SUB_EOD_MARKER))
{
ms_start = sub->start_time + subs_delay;
ms_end = sub->end_time - 1;
}
if(sub->nb_data == 0 )
return 0;
rect = sub->data;
for(i = 0;i < sub->nb_data;i++)
{
if(x_pos == -1)
{
x_pos = rect[i].x;
y_pos = rect[i].y;
width = rect[i].w;
height = rect[i].h;
}
else
{
if(x_pos > rect[i].x)
{
width += (x_pos - rect[i].x);
x_pos = rect[i].x;
}
if (rect[i].y < y_pos)
{
height += (y_pos - rect[i].y);
y_pos = rect[i].y;
}
if (rect[i].x + rect[i].w > x_pos + width)
{
width = rect[i].x + rect[i].w - x_pos;
}
if (rect[i].y + rect[i].h > y_pos + height)
{
height = rect[i].y + rect[i].h - y_pos;
}
}
}
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
pbuf = (uint8_t*) malloc(width * height);
memset(pbuf, 0x0, width * height);
for(i = 0;i < sub->nb_data;i++)
{
x_off = rect[i].x - x_pos;
y_off = rect[i].y - y_pos;
for (y = 0; y < rect[i].h; y++)
{
for (x = 0; x < rect[i].w; x++)
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
}
}
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 rectangle */
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
#ifdef ENABLE_OCR
str = ocr_bitmap(palette,alpha,pbuf,width,height);
if(str && str[0])
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
char *token = NULL;
sprintf(context->buffer,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
,(unsigned long long)ms_start);
write(context->out->fh,context->buffer,strlen(context->buffer));
token = strtok(str,"\r\n");
while (token)
{
sprintf(context->buffer,"%s",token);
token = strtok(NULL,"\r\n");
if(token)
strcat(context->buffer,"<br>\n");
else
strcat(context->buffer,"\n");
write(context->out->fh,context->buffer,strlen(context->buffer));
}
sprintf(context->buffer,
"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n"
,(unsigned long long)ms_end);
write(context->out->fh,context->buffer,strlen(context->buffer));
}
}
#endif
end:
sub->nb_data = 0;
freep(&sub->data);
freep(&palette);
freep(&alpha);
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+=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;
}

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)

File diff suppressed because it is too large Load Diff

View File

@@ -1,480 +0,0 @@
#ifndef CCX_CCEXTRACTOR_H
#define CCX_CCEXTRACTOR_H
#define VERSION "0.73"
// 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_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 ccx_boundary_time
{
int hh,mm,ss;
LLONG time_in_ms;
int set;
};
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;
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
/* 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 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_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
};
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;
};
/* Report information */
#define SUB_STREAMS_CNT 10
struct file_report_t
{
unsigned program_cnt;
unsigned width;
unsigned height;
unsigned aspect_ratio;
unsigned frame_rate;
struct ccx_decoder_608_report_t 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;
} 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 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 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);
// ccextractor.c
void init_libraries();
//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 *enc_ctx);
LLONG process_raw (struct cc_subtitle *sub);
void general_loop(void *enc_ctx);
void processhex (char *filename);
void rcwt_loop(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( void );
// wtv_functions.c
LLONG wtv_getmoredata( void );
// avc_functions.c
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen, struct cc_subtitle *sub);
void init_avc(void);
// es_functions.c
LLONG process_m2v (unsigned char *data, LLONG length, struct cc_subtitle *sub);
extern unsigned top_field_first;
// es_userdata.c
int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
// bitstream.c - see bitstream.h
// 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);
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
// sequencing.c
void init_hdcc (void);
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts, struct cc_subtitle *sub);
void anchor_hdcc(int seq);
void process_hdcc (struct cc_subtitle *sub);
int do_cb (unsigned char *cc_block, struct cc_subtitle *sub);
// mp4.c
int processmp4 (char *file,void *enc_ctx);
// 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, ccx_decoder_608_context *context, struct cc_subtitle *sub);
void flushbuffer (struct ccx_s_write *wb, int closefile);
void printdata (const unsigned char *data1, int length1,const unsigned char *data2, int length2, struct cc_subtitle *sub);
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 *enc_ctx);
// utility.c
void fatal(int exit_code, const char *fmt, ...);
void dvprint(const char *fmt, ...);
void mprint (const char *fmt, ...);
void dbg_print(LLONG mask, 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);
unsigned encode_line (unsigned char *buffer, unsigned char *text);
void buffered_seek (int offset);
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 tlt_read_rcwt();
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,
unsigned *seconds, unsigned *ms);
extern unsigned rollover_bits;
extern uint32_t global_timestamp, min_global_timestamp;
extern int global_timestamp_inited;
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 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 unsigned total_pulldownfields;
extern unsigned total_pulldownframes;
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 ccx_decoder_608_context 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 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 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;
#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 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 enum ccx_stream_mode_enum auto_stream;
extern int num_input_files;
extern char *basefilename;
extern struct ccx_s_write wbout1, wbout2, *wbxdsout;
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
*/
// 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 int PIDs_seen[65536];
extern struct PMT_entry *PIDs_programs[65536];
// extern LLONG ts_start_of_xds; // Moved to 608.h, only referenced in 608.c & xds.c
//extern int timestamps_on_transcript;
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

View File

@@ -1,100 +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 "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"
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 */
// Preencoded strings
unsigned char encoded_crlf[16];
unsigned int encoded_crlf_length;
unsigned char encoded_br[16];
unsigned int encoded_br_length;
void ccx_decoders_common_settings_init(LLONG subs_delay, enum ccx_output_format output_format){
ccx_decoders_common_settings.subs_delay = subs_delay;
ccx_decoders_common_settings.output_format = output_format;
}
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
}

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

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,11 +3,12 @@
#include <stdlib.h>
#include <gpac/isomedia.h>
#include "../ccextractor.h"
#include "../utility.h"
#include "../ccx_encoders_common.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, struct cc_subtitle *sub); // 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)
@@ -26,7 +27,7 @@ static struct {
unsigned type[32];
}s_nalu_stats;
static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
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;
@@ -61,14 +62,14 @@ static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, s
temp_debug=0;
if (nal_length>0)
do_NAL ((unsigned char *) &(s->data[i]) ,nal_length, sub);
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, struct cc_subtitle *sub)
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;
@@ -95,16 +96,16 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track, st
pts_set=1;
set_fts();
process_m2v ((unsigned char *) s->data,s->dataLength, sub);
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)
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;
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
@@ -113,7 +114,7 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track, st
return status;
}
static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
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;
@@ -154,7 +155,7 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, str
last_sdi = sdi;
}
status = process_avc_sample(timescale, c, s, sub);
status = process_avc_sample(ctx, timescale, c, s, sub);
gf_isom_sample_del(&s);
@@ -165,11 +166,11 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, str
}
int progress = (int) ((i*100) / sample_count);
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;
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
@@ -197,7 +198,7 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, str
}
*/
int processmp4 (char *file,void *enc_ctx)
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;
@@ -245,7 +246,7 @@ int processmp4 (char *file,void *enc_ctx)
{
if (cc_track_count && !ccx_options.mp4vidtrack)
continue;
if(process_xdvb_track(file, f, i + 1, &dec_sub) != 0)
if(process_xdvb_track(ctx, file, f, i + 1, &dec_sub) != 0)
{
mprint("error\n");
return -3;
@@ -267,11 +268,11 @@ int processmp4 (char *file,void *enc_ctx)
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, &dec_sub);
do_NAL (ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
}
}
if(process_avc_track(file, f, i + 1, &dec_sub) != 0)
if(process_avc_track(ctx, file, f, i + 1, &dec_sub) != 0)
{
mprint("error\n");
return -3;
@@ -349,7 +350,7 @@ int processmp4 (char *file,void *enc_ctx)
#endif
do
{
ret = process608((unsigned char*)data, len, &context_cc608_field_1, &dec_sub);
ret = process608((unsigned char*)data, len, ctx->dec_ctx->context_cc608_field_1, &dec_sub);
len -= ret;
data += ret;
if(dec_sub.got_output)
@@ -365,11 +366,11 @@ int processmp4 (char *file,void *enc_ctx)
// 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;
ctx->last_reported_progress = progress;
}
}
int cur_sec = (int) (get_fts() / 1000);
@@ -396,9 +397,9 @@ int processmp4 (char *file,void *enc_ctx)
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;
}

View File

@@ -1,4 +1,5 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "png.h"
#include "spupng_encoder.h"
@@ -6,7 +7,7 @@
#include "utility.h"
// Produces minimally-compliant SMPTE Timed Text (W3C TTML)
// format-compatible output
// format-compatible output
// See http://www.w3.org/TR/ttaf1-dfxp/ and
// https://www.smpte.org/sites/default/files/st2052-1-2010.pdf
@@ -36,7 +37,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
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);
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);
@@ -44,7 +45,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
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 *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");
@@ -56,7 +57,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
{
unescaped[pos_w]=0;
pos_r+=2;
pos_r+=2;
}
else
{
@@ -66,7 +67,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
pos_w++;
}
unescaped[pos_w]=0;
// Now read the unescaped string (now several string'z and write them)
// Now read the unescaped string (now several string'z and write them)
unsigned char *begin=unescaped;
while (begin<unescaped+len)
{
@@ -78,7 +79,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
}
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;
}
@@ -90,7 +91,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
}
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);
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);
@@ -105,135 +106,60 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
{
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
int x_pos, y_pos, width, height, i;
int x, y, y_off, x_off, ret;
uint8_t *pbuf;
//char *filename;
int ret = 0;
struct cc_bitmap* rect;
png_color *palette = NULL;
png_byte *alpha = NULL;
#ifdef ENABLE_OCR
char*str = NULL;
#endif
//int used;
#ifdef ENABLE_OCR
unsigned h1, m1, s1, ms1;
unsigned h2, m2, s2, ms2;
#endif
LLONG ms_start, ms_end;
//char timeline[128];
int len = 0;
x_pos = -1;
y_pos = -1;
width = 0;
height = 0;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start + subs_delay;
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 + subs_delay;
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;
for(i = 0;i < sub->nb_data;i++)
{
if(x_pos == -1)
{
x_pos = rect[i].x;
y_pos = rect[i].y;
width = rect[i].w;
height = rect[i].h;
}
else
{
if(x_pos > rect[i].x)
{
width += (x_pos - rect[i].x);
x_pos = rect[i].x;
}
if (rect[i].y < y_pos)
{
height += (y_pos - rect[i].y);
y_pos = rect[i].y;
}
if (rect[i].x + rect[i].w > x_pos + width)
{
width = rect[i].x + rect[i].w - x_pos;
}
if (rect[i].y + rect[i].h > y_pos + height)
{
height = rect[i].y + rect[i].h - y_pos;
}
}
}
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
pbuf = (uint8_t*) malloc(width * height);
memset(pbuf, 0x0, width * height);
for(i = 0;i < sub->nb_data;i++)
{
x_off = rect[i].x - x_pos;
y_off = rect[i].y - y_pos;
for (y = 0; y < rect[i].h; y++)
{
for (x = 0; x < rect[i].w; x++)
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
}
}
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 rectangle */
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
#ifdef ENABLE_OCR
str = ocr_bitmap(palette,alpha,pbuf,width,height);
if(str && str[0])
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, context->buffer,strlen(context->buffer) );
len = strlen(str);
write (context->out->fh, str, len);
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 ((char *) str,"</p>\n");
sprintf ( buf,"</p>\n");
write (context->out->fh, buf,strlen(buf) );
}
}
#endif
end:
sub->nb_data = 0;
freep(&sub->data);
freep(&palette);
freep(&alpha);
return ret;
}
@@ -247,16 +173,16 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
int wrote_something=0;
LLONG startms = data->start_time;
startms+=subs_delay;
startms+=context->subs_delay;
if (startms<0) // Drop screens that because of subs_delay start too early
return 0;
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);
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)
{
@@ -267,7 +193,7 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
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)
{
@@ -276,7 +202,7 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
}
write(context->out->fh, subline, length);
wrote_something=1;
write(context->out->fh, encoded_crlf, encoded_crlf_length);
}
}

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)));
@@ -196,7 +196,7 @@ int
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
struct encoder_ctx *context)
{
LLONG ms_start = data->start_time + subs_delay;
LLONG ms_start = data->start_time + context->subs_delay;
if (ms_start < 0)
{
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
@@ -263,7 +263,7 @@ spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
strncat(str,"\n",256);
}
}
write_spucomment(sp,str);
return 1;
}
@@ -276,4 +276,3 @@ int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *con
}
return 0;
}

View File

@@ -1,6 +1,6 @@
#ifndef __608_SPUPNG_H__
#include "ccextractor.h"
#include "lib_ccx.h"
#include "spupng_encoder.h"
#include "ccx_encoders_common.h"

View File

@@ -1,8 +1,6 @@
#include "ccextractor.h"
#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"
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
@@ -17,11 +15,11 @@ void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_st
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);
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\r\n",
h1,m1,s1,ms1, h2,m2,s2,ms2);
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);
@@ -74,17 +72,8 @@ void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_st
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
int x_pos, y_pos, width, height, i;
int x, y, y_off, x_off, ret;
uint8_t *pbuf;
//char *filename;
int ret = 0;
struct cc_bitmap* rect;
png_color *palette = NULL;
png_byte *alpha = NULL;
#ifdef ENABLE_OCR
char*str = NULL;
#endif
LLONG ms_start, ms_end;
#ifdef ENABLE_OCR
unsigned h1,m1,s1,ms1;
@@ -94,11 +83,6 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
int used;
#endif
x_pos = -1;
y_pos = -1;
width = 0;
height = 0;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
ms_start = context->prev_start;
@@ -109,79 +93,21 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
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;
rect = sub->data;
for(i = 0;i < sub->nb_data;i++)
{
if(x_pos == -1)
{
x_pos = rect[i].x;
y_pos = rect[i].y;
width = rect[i].w;
height = rect[i].h;
}
else
{
if(x_pos > rect[i].x)
{
width += (x_pos - rect[i].x);
x_pos = rect[i].x;
}
if (rect[i].y < y_pos)
{
height += (y_pos - rect[i].y);
y_pos = rect[i].y;
}
if (rect[i].x + rect[i].w > x_pos + width)
{
width = rect[i].x + rect[i].w - x_pos;
}
if (rect[i].y + rect[i].h > y_pos + height)
{
height = rect[i].y + rect[i].h - y_pos;
}
}
}
if ( sub->flags & SUB_EOD_MARKER )
if(sub->flags & SUB_EOD_MARKER)
context->prev_start = sub->start_time;
pbuf = (uint8_t*) malloc(width * height);
memset(pbuf, 0x0, width * height);
for(i = 0;i < sub->nb_data;i++)
{
x_off = rect[i].x - x_pos;
y_off = rect[i].y - y_pos;
for (y = 0; y < rect[i].h; y++)
{
for (x = 0; x < rect[i].w; x++)
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
}
}
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 rectangle */
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
rect = sub->data;
#ifdef ENABLE_OCR
str = ocr_bitmap(palette,alpha,pbuf,width,height);
if(str && str[0])
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
{
@@ -195,18 +121,14 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
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(str);
write (context->out->fh, str, len);
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
end:
sub->nb_data = 0;
freep(&sub->data);
freep(&palette);
freep(&alpha);
return ret;
}
@@ -233,7 +155,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
if (empty_buf) // Prevent writing empty screens. Not needed in .srt
return 0;
ms_start+=subs_delay;
ms_start+=context->subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return 0;
@@ -243,11 +165,11 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
char timeline[128];
context->srt_counter++;
sprintf(timeline, "%u\r\n", 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\r\n",
h1,m1,s1,ms1, h2,m2,s2,ms2);
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);
@@ -335,6 +257,6 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
// fprintf (wb->fh, encoded_crlf);
write (context->out->fh, encoded_crlf, encoded_crlf_length);
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,7 +30,7 @@ void activity_input_file_open (const char *filename)
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
fflush (stderr);
fflush (stderr);
}
}
@@ -59,29 +60,29 @@ void activity_library_process(enum ccx_common_logging_gui message_type, ...){
}
}
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);
}
}
@@ -90,7 +91,7 @@ void activity_input_file_closed (void)
if (ccx_options.gui_mode_reports)
{
fprintf (stderr, "###INPUTFILECLOSED\n");
fflush (stderr);
fflush (stderr);
}
}
@@ -99,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);
}
}
@@ -129,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 (CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
fatal (CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
break;
}
return rval;
@@ -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 ) )
@@ -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
@@ -458,7 +459,7 @@ LLONG asf_getmoredata(void)
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)
{
@@ -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;
@@ -974,10 +975,10 @@ LLONG asf_getmoredata(void)
asf_data_container.PayloadLength : (BUFSIZE - inbuf));
if (want < (long)asf_data_container.PayloadLength)
fatal(CCX_COMMON_EXIT_BUG_BUG, "Buffer size to small for ASF payload!\nPlease file a bug report!\n");
buffered_read (buffer+inbuf,want);
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, struct cc_subtitle *sub);
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, struct cc_subtitle *sub)
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, struct cc_subtitle *sub)
{
// 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, sub);
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, struct cc_subtitle *sub)
// 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 ,struct cc_subtitle *sub)
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
{
unsigned char *bpos = avcbuf;
unsigned char *NALstart;
@@ -110,14 +112,14 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *s
{
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(CCX_COMMON_EXIT_BUG_BUG,
"Broken AVC stream - no 0x0000 ...");
}
}
bpos = bpos+2;
int firstloop=1; // Check for valid start code at buffer start
@@ -202,17 +204,17 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *s
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, sub);
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");
@@ -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++;
@@ -583,8 +585,8 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
dvprint("level_idc= % 4lld (%#llX)\n",tmp,tmp);
seq_parameter_set_id = ue(&q1);
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", seq_parameter_set_id,seq_parameter_set_id);
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
|| profile_idc == 244 || profile_idc == 44 || profile_idc == 83
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);
@@ -646,7 +648,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
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);
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.
}
@@ -654,18 +656,18 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
{
// CFS: Untested, just copied from specs.
tmp= u(&q1,1);
dvprint("delta_pic_order_always_zero_flag= % 4lld (%#llX)\n",tmp,tmp);
dvprint("delta_pic_order_always_zero_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp = se(&q1);
dvprint("offset_for_non_ref_pic= % 4lld (%#llX)\n",tmp,tmp);
dvprint("offset_for_non_ref_pic= % 4lld (%#llX)\n",tmp,tmp);
tmp = se(&q1);
dvprint("offset_for_top_to_bottom_field % 4lld (%#llX)\n",tmp,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 % 4lld (%#llX)\n", num_ref_frame_in_pic_order_cnt_cycle,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] = % 4lld (%#llX)\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp,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
{
@@ -673,7 +675,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
}
tmp=ue(&q1);
dvprint("max_num_ref_frames= % 4lld (%#llX)\n",tmp,tmp);
dvprint("max_num_ref_frames= % 4lld (%#llX)\n",tmp,tmp);
tmp=u(&q1,1);
dvprint("gaps_in_frame_num_value_allowed_flag= % 4lld (%#llX)\n",tmp,tmp);
tmp=ue(&q1);
@@ -782,21 +784,21 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
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);
@@ -817,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, struct cc_subtitle *sub)
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;
@@ -903,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;
@@ -923,7 +925,7 @@ 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(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type != 0 not yet supported.");
//TODO
@@ -965,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
@@ -982,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(sub);
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;
@@ -1035,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;
}
}
@@ -1078,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;
}
}
@@ -1098,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
@@ -1112,9 +1114,9 @@ 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, sub);
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;
}

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;
@@ -300,11 +300,11 @@ uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
}
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

@@ -13,5 +13,8 @@
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);
#endif
extern int cc608_parity_table[256]; // From myth
#endif

View File

@@ -124,10 +124,15 @@ enum
DTVCC_PACKET_START = 3,
};
const char *language[4] =
/**
* 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

@@ -39,16 +39,16 @@ extern 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_DECODER_608=0x10, // Show CC-608 decoder debug?
CCX_DMT_708=0x20, // Show CC-708 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
@@ -81,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,
@@ -108,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,
@@ -124,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,
};
@@ -222,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,
};
/*
@@ -236,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
@@ -265,5 +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
extern const char *language[4];
#define NB_LANGUAGE 5
extern const char *language[NB_LANGUAGE];
#endif

View File

@@ -0,0 +1,105 @@
#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->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;
// 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,98 @@
#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?
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;
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

@@ -7,7 +7,7 @@
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
@@ -86,8 +86,8 @@
#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
// 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
@@ -97,7 +97,7 @@
#define TELL tell
#include <stdint.h>
#endif
#endif
#endif
#ifndef int64_t_C
#define int64_t_C(c) (c ## LL)

View File

@@ -9,12 +9,13 @@ enum ccx_common_logging_gui {
};
struct ccx_common_logging_t {
int debug_mask; // The debug mask that is used to determine if things should be printed or not.
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)
} ccx_common_logging;
};
extern struct ccx_common_logging_t ccx_common_logging;
enum subtype
{
@@ -49,4 +50,4 @@ struct cc_subtitle
/** flag to tell that decoder has given output */
int got_output;
};
#endif
#endif

View File

@@ -41,7 +41,10 @@ struct gop_time_code gop_time, first_gop_time, printed_gop;
LLONG fts_at_gop_start = 0;
int gop_rollover = 0;
void ccx_common_timing_init(LLONG *file_position,int no_sync){
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;
@@ -111,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;
@@ -228,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));
@@ -286,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

@@ -19,7 +19,15 @@ struct ccx_common_timing_settings_t {
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
} ccx_common_timing_settings;
};
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;
@@ -61,4 +69,4 @@ int gop_accepted(struct gop_time_code* g);
void calculate_ms_gop_time(struct gop_time_code *g);
#define __Timing_H__
#endif
#endif

View File

@@ -116,42 +116,54 @@ void clear_eia608_cc_buffer(ccx_decoder_608_context *context, struct eia608_scre
data->empty=1;
}
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)
void ccx_decoder_608_dinit_library(void **ctx)
{
ccx_decoder_608_context data;
freep(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)
{
ccx_decoder_608_context *data = NULL;
data.cursor_column=0;
data.cursor_row=0;
data.visible_buffer=1;
data.last_c1=0;
data.last_c2=0;
data.mode=MODE_POPON;
// data.current_visible_start_cc=0;
data.current_visible_start_ms=0;
data.screenfuls_counter=0;
data.channel=1;
data.font=FONT_REGULAR;
data.rollup_base_row=14;
data.ts_start_of_current_line=-1;
data.ts_last_char_received=-1;
data.new_channel=1;
data.bytes_processed_608 = 0;
data.my_field = field;
data.my_channel = channel;
data.out = NULL;
data.have_cursor_position = 0;
data = malloc(sizeof(ccx_decoder_608_context));
data.trim_subs = trim_subs;
data.encoding = encoding;
data.halt = halt;
data.cc_to_stdout = cc_to_stdout;
data->cursor_column=0;
data->cursor_row=0;
data->visible_buffer=1;
data->last_c1=0;
data->last_c2=0;
data->mode=MODE_POPON;
// data->current_visible_start_cc=0;
data->current_visible_start_ms=0;
data->screenfuls_counter=0;
data->channel=1;
data->font=FONT_REGULAR;
data->rollup_base_row=14;
data->ts_start_of_current_line=-1;
data->ts_last_char_received=-1;
data->new_channel=1;
data->bytes_processed_608 = 0;
data->my_field = field;
data->my_channel = channel;
data->out = NULL;
data->have_cursor_position = 0;
data.settings = settings;
data.current_color = data.settings.default_color;
data->trim_subs = trim_subs;
data->encoding = encoding;
clear_eia608_cc_buffer(&data, &data.buffer1);
clear_eia608_cc_buffer(&data, &data.buffer2);
data->halt = halt;
data->cc_to_stdout = cc_to_stdout;
data->subs_delay = subs_delay;
data->output_format = output_format;
data->settings = settings;
data->current_color = data->settings.default_color;
clear_eia608_cc_buffer(data, &data->buffer1);
clear_eia608_cc_buffer(data, &data->buffer2);
return data;
}
@@ -284,7 +296,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
*context->halt=1;
return 0;
}
data = get_current_visible_buffer(context);
if (context->mode == MODE_FAKE_ROLLUP_1 && // Use the actual start of data instead of last buffer change
@@ -292,7 +304,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
context->current_visible_start_ms = context->ts_start_of_current_line;
start_time = context->current_visible_start_ms;
end_time = get_visible_end() + ccx_decoders_common_settings.subs_delay;
end_time = get_visible_end() + context->subs_delay;
sub->type = CC_608;
data->format = SFORMAT_CC_SCREEN;
data->start_time = 0;
@@ -347,17 +359,18 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
int wrote_something=0;
int ret = 0;
data = get_current_visible_buffer(context);
start_time = context->ts_start_of_current_line + ccx_decoders_common_settings.subs_delay;
end_time = get_fts() + ccx_decoders_common_settings.subs_delay;
start_time = context->ts_start_of_current_line + context->subs_delay;
end_time = get_fts() + context->subs_delay;
sub->type = CC_608;
data->format = SFORMAT_CC_LINE;
data->format = SFORMAT_CC_LINE;
data->start_time = 0;
data->end_time = 0;
data->mode = context->mode;
data->channel = context->channel;
data->my_field = context->my_field;
//TODO need to put below functionality in encoder context
ret = get_decoder_line_basic (subline, context->cursor_row, data,context->trim_subs,context->encoding);
if( ret > 0 )
{
@@ -400,7 +413,7 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
}
}
return wrote_something;
}
// Check if a rollup would cause a line to go off the visible area
@@ -728,7 +741,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
context->cursor_row++;
break;
}
if (ccx_decoders_common_settings.output_format == CCX_OF_TRANSCRIPT)
if (context->output_format == CCX_OF_TRANSCRIPT)
{
write_cc_line(context,sub);
}
@@ -739,7 +752,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
if (changes)
{
// Only if the roll up would actually cause a line to disappear we write the buffer
if (ccx_decoders_common_settings.output_format != CCX_OF_TRANSCRIPT)
if (context->output_format != CCX_OF_TRANSCRIPT)
{
if (write_cc_buffer(context, sub))
context->screenfuls_counter++;
@@ -759,7 +772,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
case COM_ERASEDISPLAYEDMEMORY:
// Write it to disk before doing this, and make a note of the new
// time it became clear.
if (ccx_decoders_common_settings.output_format == CCX_OF_TRANSCRIPT &&
if (context->output_format == CCX_OF_TRANSCRIPT &&
(context->mode == MODE_FAKE_ROLLUP_1 ||
context->mode == MODE_ROLLUP_2 ||
context->mode == MODE_ROLLUP_3 ||
@@ -772,7 +785,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
}
else
{
if (ccx_decoders_common_settings.output_format == CCX_OF_TRANSCRIPT)
if (context->output_format == CCX_OF_TRANSCRIPT)
context->ts_start_of_current_line = context->current_visible_start_ms;
if (write_cc_buffer(context, sub))
context->screenfuls_counter++;
@@ -939,7 +952,7 @@ void handle_pac(unsigned char c1, unsigned char c2, ccx_decoder_608_context *con
memset(use_buffer->colors[j], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH);
memset(use_buffer->fonts[j], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH);
use_buffer->characters[j][CCX_DECODER_608_SCREEN_WIDTH] = 0;
use_buffer->row_used[j]=0;
use_buffer->row_used[j] = 0;
}
}
}
@@ -1065,10 +1078,14 @@ int disCommand(unsigned char hi, unsigned char lo, ccx_decoder_608_context *cont
/* If wb is NULL, then only XDS will be processed */
int process608(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub)
{
struct ccx_decoder_608_report *report = NULL;
static int textprinted = 0;
int i;
if (context)
{
report = &context->report;
context->bytes_processed_608 += length;
}
if (!data)
{
return -1;
@@ -1091,7 +1108,8 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
if (context == NULL || context->my_field == 2) // Originally: current_field from sequencing.c. Seems to be just to change channel, so context->my_field seems good.
ch+=2;
ccx_decoder_608_report.cc_channels[ch - 1] = 1;
if(report)
report->cc_channels[ch - 1] = 1;
}
if (hi >= 0x01 && hi <= 0x0E && (context == NULL || context->my_field == 2)) // XDS can only exist in field 2.
@@ -1103,8 +1121,8 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
ts_start_of_xds=get_fts();
in_xds_mode=1;
}
ccx_decoder_608_report.xds=1;
if(report)
report->xds=1;
}
if (hi == 0x0F && in_xds_mode && (context == NULL || context->my_field == 2)) // End of XDS block
{
@@ -1197,7 +1215,7 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
context->current_visible_start_ms = get_visible_start();
}
}
if (wrote_to_screen && *context->cc_to_stdout)
if (wrote_to_screen && context->cc_to_stdout)
fflush (stdout);
} // for
return i;

View File

@@ -6,22 +6,24 @@
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_t {
struct ccx_decoder_608_report
{
unsigned xds : 1;
unsigned cc_channels[4];
} ccx_decoder_608_report;
};
typedef struct ccx_decoder_608_settings {
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 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
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
} ccx_decoder_608_settings;
typedef struct ccx_decoder_608_context
@@ -41,22 +43,25 @@ typedef struct ccx_decoder_608_context
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 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 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.
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 char str[2048];
extern unsigned enc_buffer_used;
extern unsigned enc_buffer_capacity;
@@ -112,10 +117,15 @@ enum command_code
};
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);
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
@@ -139,11 +149,6 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
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);
unsigned char *debug_608toASC(unsigned char *ccdata, int channel);
//void delete_all_lines_but_current(ccx_decoder_608_context *context, struct eia608_screen *data, int row);
LLONG get_visible_end(void);
#define __608_H__
#endif
#endif

View File

@@ -6,12 +6,14 @@
/* 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
@@ -31,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]=
@@ -71,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},
@@ -100,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++)
{
@@ -108,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;
@@ -119,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)
{
ccx_common_logging.debug_ftn(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)
@@ -150,35 +157,35 @@ void clearTV (cc708_service_decoder *decoder, int buffer) // Buffer => 1 or 2
void printTVtoSRT (cc708_service_decoder *decoder, int which)
{
if (ccx_decoders_common_settings.output_format == CCX_OF_NULL)
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() + ccx_decoders_common_settings.subs_delay;
LLONG ms_end = get_visible_end() + decoder->subs_delay;
int empty=1;
ms_start+= ccx_decoders_common_settings.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
{
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?
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)
{
@@ -187,13 +194,13 @@ void printTVtoSRT (cc708_service_decoder *decoder, int which)
}
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;
@@ -210,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);
}
}
@@ -283,7 +290,7 @@ void updateScreen (cc708_service_decoder *decoder)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "%d (%d) | ",wnd[i]->number, wnd[i]->priority);
}
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
for (int i=0;i<visible;i++)
{
int top,left;
@@ -345,13 +352,13 @@ void updateScreen (cc708_service_decoder *decoder)
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!
@@ -376,22 +383,22 @@ int handle_708_C3 (cc708_service_decoder *decoder, unsigned char *data, int data
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
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;
{
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];
@@ -456,7 +463,7 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
name="Reserved";
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])
@@ -465,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
@@ -497,20 +504,20 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
{
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)
{
{
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;
@@ -568,7 +575,7 @@ 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)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_CWx_SetCurrentWindow, new window: [%d]\n",new_window);
@@ -594,17 +601,17 @@ void handle_708_CLW_ClearWindows (cc708_service_decoder *decoder, int windows_bi
if (windows_bitmap & 1)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
clearWindow (decoder, i);
clearWindow (decoder, i);
}
windows_bitmap>>=1;
}
}
ccx_common_logging.debug_ftn(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)
{
ccx_common_logging.debug_ftn(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)
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
else
@@ -619,14 +626,14 @@ void handle_708_DSW_DisplayWindows (cc708_service_decoder *decoder, int windows_
{
changes=1;
decoder->windows[i].visible=1;
}
}
}
windows_bitmap>>=1;
}
ccx_common_logging.debug_ftn(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)
@@ -654,7 +661,7 @@ void handle_708_HDW_HideWindows (cc708_service_decoder *decoder, int windows_bit
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)
@@ -669,13 +676,13 @@ void handle_708_TGW_ToggleWindows (cc708_service_decoder *decoder, int windows_b
if (windows_bitmap & 1)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
decoder->windows[i].visible=!decoder->windows[i].visible;
decoder->windows[i].visible=!decoder->windows[i].visible;
}
windows_bitmap>>=1;
}
updateScreen(decoder);
}
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
}
void clearWindowText (e708Window *window)
@@ -712,7 +719,7 @@ 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;
ccx_common_logging.debug_ftn(CCX_DMT_708, " Priority: [%d] Column lock: [%3s] Row lock: [%3s]\n",
@@ -742,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)
@@ -752,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;
@@ -769,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);
@@ -846,7 +853,7 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
{
if (windows_bitmap & 1)
{
ccx_common_logging.debug_ftn(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);
@@ -854,7 +861,7 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
windows_bitmap>>=1;
}
}
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
if (changes)
updateScreen (decoder);
@@ -862,7 +869,7 @@ 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)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_SPA_SetPenAttributes, attributes: \n");
@@ -876,7 +883,7 @@ void handle_708_SPA_SetPenAttributes (cc708_service_decoder *decoder, unsigned c
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);
ccx_common_logging.debug_ftn(CCX_DMT_708, " Edge type: [%d] Underline: [%d] Italic: [%d]\n",
edge_type, underline, italic);
edge_type, underline, italic);
if (decoder->current_window==-1)
{
// Can't do anything yet - we need a window to be defined first.
@@ -938,7 +945,7 @@ 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)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DLY_Delay, delay for [%d] tenths of second.", tenths_of_sec);
@@ -958,7 +965,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
struct S_COMMANDS_C1 com=COMMANDS_C1[data[0]-0x80];
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)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "C1: Warning: Not enough bytes for command.\n");
@@ -977,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]);
@@ -1008,7 +1015,7 @@ 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:
@@ -1017,7 +1024,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
break;
case SWA:
handle_708_SWA_SetWindowAttributes (decoder, data);
break;
break;
case DF0:
case DF1:
case DF2:
@@ -1027,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:
ccx_common_logging.log_ftn ("BUG: Unhandled code in handle_708_C1.\n");
break;
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
@@ -1068,20 +1075,20 @@ void process_service_block (cc708_service_decoder *decoder, unsigned char *data,
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
@@ -1091,31 +1098,31 @@ void process_current_packet (void)
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
#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?
{
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,
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)
{
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)
{
@@ -1123,25 +1130,25 @@ void process_current_packet (void)
int block_length = (pos[0] & 0x1F); // 5 less significant bits
ccx_common_logging.debug_ftn (CCX_DMT_708, "Standard header: Service number: [%d] Block length: [%d]\n",service_number,
block_length);
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)
{
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;
}
} */
@@ -1159,8 +1166,8 @@ void process_current_packet (void)
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();
@@ -1168,38 +1175,38 @@ void process_current_packet (void)
if (pos!=current_packet+len) // For some reason we didn't parse the whole packet
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "There was a problem with this packet, reseting\n");
cc708_reset();
cc708_reset(ctx);
}
if (len<128 && *pos) // Null header is mandatory if there is room
{
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_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:
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)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
}
@@ -1210,12 +1217,12 @@ void do_708 (const unsigned char *data, int datalength)
}
}
break;
case 3:
case 3:
ccx_common_logging.debug_ftn (CCX_DMT_708, "708: DTVCC Channel Packet Start\n");
process_current_packet();
process_current_packet(ctx);
if (cc_valid)
{
if (current_packet_length>127)
if (current_packet_length>127)
{
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
}
@@ -1226,7 +1233,7 @@ void do_708 (const unsigned char *data, int datalength)
}
}
break;
default:
default:
ccx_common_logging.fatal_ftn (CCX_COMMON_EXIT_BUG_BUG, "708: shouldn't be here - cc_type: %d\n", cc_type);
}
}
@@ -1241,11 +1248,11 @@ void ccx_decoders_708_init_library(char *basefilename,const char *extension,int
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

@@ -8,7 +8,7 @@
#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
@@ -20,9 +20,11 @@ This variable (ccx_decoder_708_report) holds data on the cc channels & xds packe
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 {
struct ccx_decoder_708_report_t
{
unsigned services[CCX_DECODERS_708_MAX_SERVICES];
} ccx_decoder_708_report;
};
extern struct ccx_decoder_708_report_t ccx_decoder_708_report;
enum COMMANDS_C0_CODES
{
@@ -54,7 +56,7 @@ enum COMMANDS_C1_CODES
DLY=0x8D,
DLC=0x8E,
RST=0x8F,
SPA=0x90,
SPA=0x90,
SPC=0x91,
SPL=0x92,
RSV93=0x93,
@@ -273,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
@@ -289,6 +291,8 @@ 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;
@@ -297,7 +301,7 @@ extern int cea708services[]; // [] -> 1 for services to be processed
extern int resets_708;
void do_708 (const unsigned char *data, int datalength);
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);
@@ -306,4 +310,4 @@ 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
#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

@@ -3,6 +3,7 @@
#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
@@ -22,4 +23,12 @@ void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_
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

@@ -1,7 +1,9 @@
#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
@@ -17,6 +19,9 @@ struct cc_bitmap
int nb_colors;
unsigned char *data[2];
int linesize[2];
#ifdef ENABLE_OCR
char *ocr_text;
#endif
};
enum ccx_eia608_format
@@ -70,10 +75,31 @@ typedef struct eia608_screen // A CC buffer
int cur_xds_packet_class;
} eia608_screen;
struct ccx_decoderrs_common_settings_t {
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?
} ccx_decoders_common_settings;
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.
#define CCX_DECODERS_STRUCTS_H
#endif
/* 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;
LLONG subs_delay; // ms to delay (or advance) subs
};
#endif

View File

@@ -20,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];
@@ -101,12 +101,12 @@ 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
@@ -120,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;
@@ -196,7 +196,7 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time,
if (!wb || wb->fh==-1)
return;
if (start_time == -1)
if (start_time == -1)
{
// Means we entered XDS mode without making a note of the XDS start time. This is a bug.
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
@@ -254,7 +254,7 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time,
if (ccx_decoders_xds_context.transcriptFormat.showCC){
fdprintf(wb->fh, "%s|", XDSclasses_short[cur_xds_packet_class]);
}
}
}
void xdsprint (struct cc_subtitle *sub,const char *fmt,...)
{
@@ -283,14 +283,14 @@ void xdsprint (struct cc_subtitle *sub,const char *fmt,...)
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);
return ;
} else {
p = np;
}
}
}
}
void xds_debug_test(struct cc_subtitle *sub)
@@ -336,7 +336,7 @@ void clear_xds_buffer (int num)
}
void process_xds_bytes (const unsigned char hi, int lo)
{
{
int is_new;
if (hi>=0x01 && hi<=0x0f)
{
@@ -347,7 +347,7 @@ void process_xds_bytes (const unsigned char hi, int lo)
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)
{
@@ -357,7 +357,7 @@ 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.
@@ -378,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)
{
@@ -401,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 (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;
@@ -431,11 +431,11 @@ void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned
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]);
@@ -450,7 +450,7 @@ void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned
xdsprint(sub, aps);
xdsprint(sub, rcd);
}
if (changed)
if (changed)
{
ccx_common_logging.log_ftn ("\rXDS: %s\n",copy_permited);
ccx_common_logging.log_ftn ("\rXDS: %s\n",aps);
@@ -489,14 +489,14 @@ void xds_do_content_advisory (struct cc_subtitle *sub, 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;
@@ -526,8 +526,8 @@ void xds_do_content_advisory (struct cc_subtitle *sub, 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;
@@ -536,13 +536,13 @@ void xds_do_content_advisory (struct cc_subtitle *sub, 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
{
{
if (ccx_decoders_xds_context.transcriptFormat.xds)
{
xdsprint(sub, age);
xdsprint(sub, content);
}
if (changed)
if (changed)
{
ccx_common_logging.log_ftn ("\rXDS: %s\n ",age);
ccx_common_logging.log_ftn ("\rXDS: %s\n ",content);
@@ -552,18 +552,18 @@ void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
}
if (!a0 || // MPA
(a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
)
)
{
if (ccx_decoders_xds_context.transcriptFormat.xds)
xdsprint(sub, rating);
if (changed)
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)
if (changed && !supported)
ccx_common_logging.log_ftn ("XDS: Unsupported ContentAdvisory encoding, please submit sample.\n");
}
@@ -614,7 +614,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
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:
@@ -624,7 +624,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
break;
int min=cur_xds_payload[2] & 0x3f; // 6 bits
int hour = cur_xds_payload[3] & 0x1f; // 5 bits
if (!xds_program_length_shown)
if (!xds_program_length_shown)
ccx_common_logging.log_ftn ("\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
else
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
@@ -646,7 +646,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
}
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)
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, ":%02d",el_sec);
if (ccx_decoders_xds_context.transcriptFormat.xds)
@@ -670,7 +670,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
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 &&
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)
@@ -682,7 +682,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
}
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)
@@ -709,9 +709,9 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
*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)
ccx_common_logging.log_ftn ("[%02X-", cur_xds_payload[i]);
if (ccx_decoders_xds_context.transcriptFormat.xds)
@@ -725,10 +725,10 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
if (!current_program_type_reported)
{
if (cur_xds_payload[i]>=0x20 && cur_xds_payload[i]<0x7F)
ccx_common_logging.log_ftn ("%s",XDSProgramTypes[cur_xds_payload[i]-0x20]);
ccx_common_logging.log_ftn ("%s",XDSProgramTypes[cur_xds_payload[i]-0x20]);
else
ccx_common_logging.log_ftn ("ILLEGAL VALUE");
ccx_common_logging.log_ftn ("] ");
ccx_common_logging.log_ftn ("] ");
}
}
if (ccx_decoders_xds_context.transcriptFormat.xds)
@@ -736,18 +736,18 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
if (!current_program_type_reported)
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 (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;
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:
@@ -766,9 +766,9 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
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;
@@ -778,7 +778,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
strcpy (xds_program_description[line_num], xds_desc);
}
else
{
{
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS description line %d: %s\n",line_num,xds_desc);
}
if (ccx_decoders_xds_context.transcriptFormat.xds)
@@ -819,13 +819,13 @@ int xds_do_channel (struct cc_subtitle *sub)
was_proc=1;
char xds_call_letters[7];
if (cur_xds_payload_length != 7 && cur_xds_payload_length != 9) // We need 4-6 data bytes
break;
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;
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);
@@ -838,11 +838,11 @@ int xds_do_channel (struct cc_subtitle *sub)
}
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;
@@ -874,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;
@@ -884,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;
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);
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:
@@ -900,13 +900,13 @@ int xds_do_misc ()
int dst = (cur_xds_payload[2] & 0x20) >>5; // Daylight Saving Time
int hour = cur_xds_payload[2] & 0x1f; // 5 bits
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Local Time Zone: %02d DST: %d\n",
hour, dst);
hour, dst);
break;
}
default:
was_proc=0;
break;
}
}
return was_proc;
}
@@ -915,12 +915,12 @@ 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++)
{
@@ -935,15 +935,15 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
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)
{
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);
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
{
@@ -956,21 +956,21 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
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
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(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.
// 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;
@@ -979,7 +979,7 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
was_proc = 1;
break;
}
if (!was_proc)
{
ccx_common_logging.log_ftn ("Note: We found an currently unsupported XDS packet.\n");

View File

@@ -1,4 +1,3 @@
//#include "ccextractor.h"
#include "ccx_decoders_common.h"
#include "ccx_encoders_common.h"
#include "spupng_encoder.h"
@@ -7,6 +6,7 @@
#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 =
@@ -17,7 +17,8 @@ ccx_encoders_transcript_format ccx_encoders_default_transcript_settings =
.showCC = 0,
.relativeTimestamp = 1,
.xds = 0,
.useColors = 1
.useColors = 1,
.isFinal = 0
};
static const char *sami_header= // TODO: Revise the <!-- comments
@@ -33,11 +34,18 @@ text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; colo
</HEAD>\n\n\
<BODY>\n";
static const char *smptett_header =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\
<tt xmlns=\"http://www.w3.org/ns/ttml\" xml:lang=\"en\">\n\
<body>\n<div>\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;
@@ -53,7 +61,7 @@ void write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
write(out->fh, ctx->buffer, used);
break;
case CCX_OF_SMPTETT:
sprintf ((char *) str,"</div></body></tt>\n");
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);
@@ -92,10 +100,10 @@ void write_subtitle_file_header(struct encoder_ctx *ctx,struct ccx_s_write *out)
if (ccx_options.teletext_mode == CCX_TXT_IN_USE)
rcwt_header[7] = 2; // sets file format version
write(out->fh, rcwt_header, sizeof(rcwt_header));
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:
@@ -139,13 +147,13 @@ void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx
if (ccx_options.transcript_settings.showStartTime){
char buf1[80];
if (ccx_options.transcript_settings.relativeTimestamp){
millis_to_date(start_time + subs_delay, buf1);
millis_to_date(start_time + context->subs_delay, buf1);
fdprintf(context->out->fh, "%s|", buf1);
}
else {
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
time_t start_time_int = (start_time + subs_delay) / 1000;
int start_time_dec = (start_time + subs_delay) % 1000;
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);
@@ -159,9 +167,9 @@ void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx
fdprintf(context->out->fh, "%s|", buf2);
}
else {
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
time_t end_time_int = end_time / 1000;
int end_time_dec = end_time % 1000;
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);
@@ -224,119 +232,40 @@ int write_cc_buffer_as_transcript2(struct eia608_screen *data, struct encoder_ct
}
int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
{
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
int x_pos, y_pos, width, height, i;
int x, y, y_off, x_off, ret;
uint8_t *pbuf;
//char *filename;
int ret = 0;
struct cc_bitmap* rect;
png_color *palette = NULL;
png_byte *alpha = NULL;
#ifdef ENABLE_OCR
char*str = NULL;
#endif
//int used;
#ifdef ENABLE_OCR
unsigned h1,m1,s1,ms1;
unsigned h2,m2,s2,ms2;
#endif
LLONG start_time, end_time;
//char timeline[128];
int len = 0;
x_pos = -1;
y_pos = -1;
width = 0;
height = 0;
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
{
start_time = context->prev_start + subs_delay;
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 + subs_delay;
start_time = sub->start_time + context->subs_delay;
end_time = sub->end_time - 1;
}
if(sub->nb_data == 0 )
return 0;
return ret;
rect = sub->data;
for(i = 0;i < sub->nb_data;i++)
{
if(x_pos == -1)
{
x_pos = rect[i].x;
y_pos = rect[i].y;
width = rect[i].w;
height = rect[i].h;
}
else
{
if(x_pos > rect[i].x)
{
width += (x_pos - rect[i].x);
x_pos = rect[i].x;
}
if (rect[i].y < y_pos)
{
height += (y_pos - rect[i].y);
y_pos = rect[i].y;
}
if (rect[i].x + rect[i].w > x_pos + width)
{
width = rect[i].x + rect[i].w - x_pos;
}
if (rect[i].y + rect[i].h > y_pos + height)
{
height = rect[i].y + rect[i].h - y_pos;
}
}
}
if ( sub->flags & SUB_EOD_MARKER )
context->prev_start = sub->start_time;
pbuf = (uint8_t*) malloc(width * height);
memset(pbuf, 0x0, width * height);
for(i = 0;i < sub->nb_data;i++)
{
x_off = rect[i].x - x_pos;
y_off = rect[i].y - y_pos;
for (y = 0; y < rect[i].h; y++)
{
for (x = 0; x < rect[i].w; x++)
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
}
}
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 rectangle */
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
#ifdef ENABLE_OCR
str = ocr_bitmap(palette,alpha,pbuf,width,height);
if(str && str[0])
#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(str,"\r\n");
token = strtok(rect[0].ocr_text ,"\r\n");
while (token)
{
@@ -345,14 +274,14 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
char buf1[80];
if (ccx_options.transcript_settings.relativeTimestamp)
{
millis_to_date(start_time + subs_delay, buf1);
millis_to_date(start_time + context->subs_delay, buf1);
fdprintf(context->out->fh, "%s|", buf1);
}
else
{
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
time_t start_time_int = (start_time + subs_delay) / 1000;
int start_time_dec = (start_time + subs_delay) % 1000;
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);
@@ -369,7 +298,7 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
}
else
{
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
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);
@@ -394,11 +323,8 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
}
#endif
end:
sub->nb_data = 0;
freep(&sub->data);
freep(&palette);
freep(&alpha);
return ret;
}
@@ -407,7 +333,7 @@ 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()-last_displayed_subs_ms-1;
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 ?
@@ -436,17 +362,17 @@ void try_to_add_end_credits(struct encoder_ctx *context, struct ccx_s_write *out
void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
{
LLONG st, end, window, length;
LLONG l = start_ms + subs_delay;
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 (last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
if (context->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
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);
@@ -460,7 +386,7 @@ void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
window : ccx_options.startcreditsforatmost.time_in_ms;
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
last_displayed_subs_ms, l);
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);
@@ -488,7 +414,7 @@ void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
// Do nothing for the rest
break;
}
startcredits_displayed=1;
context->startcredits_displayed=1;
return;
@@ -508,7 +434,18 @@ int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *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)
{
@@ -521,16 +458,19 @@ void dinit_encoder(struct encoder_ctx *ctx)
int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
{
int wrote_something = 0 ;
if (ccx_options.extract!=1)
context++;
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)
@@ -548,17 +488,17 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
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 (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
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 (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
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;
@@ -572,7 +512,7 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
break;
}
if (wrote_something)
last_displayed_subs_ms=get_fts()+subs_delay;
context->last_displayed_subs_ms=get_fts() + context->subs_delay;
if (ccx_options.gui_mode_reports)
write_cc_buffer_to_gui(sub->data, context);
@@ -584,15 +524,15 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
switch (ccx_options.write_format)
{
case CCX_OF_SRT:
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
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 (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
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 (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
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:
@@ -628,7 +568,7 @@ void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *cont
ms_start = data->start_time;
ms_start += subs_delay;
ms_start += context->subs_delay;
if (ms_start<0) // Drop screens that because of subs_delay start too early
return;
int time_reported = 0;

View File

@@ -14,8 +14,8 @@ if (ctx->buffer == NULL) { fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bai
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
/**
* Context of encoder, This structure gives single interface
* to all encoder
* Context of encoder, This structure gives single interface
* to all encoder
*/
struct encoder_ctx
{
@@ -29,6 +29,10 @@ struct encoder_ctx
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
@@ -40,24 +44,24 @@ struct encoder_ctx
*
* @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
* try to add end credits in subtitle file and then write subtitle
* footer
*
* deallocate encoder ctx, so before using encoder_ctx again
* 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 ctx encoder context
* @param sub subtitle context returned by decoder
*/
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
@@ -78,4 +82,7 @@ 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

@@ -17,7 +17,7 @@ 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[] =
@@ -97,7 +97,7 @@ void capitalize(int line_num, struct eia608_screen *data)
// Encodes a generic string. Note that since we use the encoders for closed caption
// data, text would have to be encoded as CCs... so using special characters here
// it's a bad idea.
// it's a bad idea.
unsigned encode_line(unsigned char *buffer, unsigned char *text)
{
unsigned bytes = 0;
@@ -194,7 +194,7 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
buffer += encode_line(buffer, (unsigned char*)color_text[its_col][1]);
if (its_col == COL_USERDEFINED)
{
// The previous sentence doesn't copy the whole
// 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*) "\">");
@@ -334,7 +334,7 @@ int add_word(const char *word)
}
int add_built_in_words()
int add_built_in_words(void)
{
if (!spell_builtin_added)
{
@@ -356,7 +356,7 @@ int add_built_in_words()
* @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
* @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)
{
@@ -378,7 +378,8 @@ void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, con
free(tmp);
}
void ccx_encoders_helpers_perform_shellsort_words(){
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);
}

View File

@@ -18,7 +18,8 @@ struct ccx_encoders_helpers_settings_t {
int no_font_color;
int no_type_setting;
enum ccx_encoding_type encoding;
} ccx_encoders_helpers_settings;
};
extern struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
// Helper functions
void correct_case(int line_num, struct eia608_screen *data);
@@ -28,11 +29,11 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
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();
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 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
#endif

View File

@@ -1,13 +1,14 @@
#ifndef CCX_ENCODERS_STRUCTS_H
typedef struct {
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 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;
@@ -21,4 +22,4 @@ struct ccx_s_write
};
#define CCX_ENCODERS_STRUCTS_H
#endif
#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"
@@ -43,7 +44,7 @@ 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},
{"BUFFER_INPUT",offsetof(struct ccx_s_options,buffer_input),set_int},
{"NOFONT_COLOR",offsetof(struct ccx_s_options,nofontcolor),set_int},
{"NOTYPE_SETTING",offsetof(struct ccx_s_options,notypesetting),set_int},
{"CODEC",offsetof(struct ccx_s_options,codec),set_int},
@@ -59,7 +60,7 @@ struct conf_map configuration_map[] = {
{"END_CREDITS_FOR_ATMOST",offsetof(struct ccx_s_options,endcreditsforatmost),set_time},
{"VIDEO_EDITED",offsetof(struct ccx_s_options,binary_concat),set_int},
{"GOP_TIME",offsetof(struct ccx_s_options,use_gop_as_pts),set_int},
{"FIX_PADDINDG",offsetof(struct ccx_s_options,fix_padding),set_int},
{"FIX_PADDINDG",offsetof(struct ccx_s_options,fix_padding),set_int},
{"TRIM",offsetof(struct ccx_s_options,trim_subs),set_int},
{"GUI_MODE_REPORTS",offsetof(struct ccx_s_options,gui_mode_reports),set_int},
{"NO_PROGRESS_BAR",offsetof(struct ccx_s_options,no_progress_bar),set_int},
@@ -67,7 +68,7 @@ struct conf_map configuration_map[] = {
{"CAP_FILE",offsetof(struct ccx_s_options,sentence_cap_file),set_string},
{"PROGRAM_NUMBER",offsetof(struct ccx_s_options,ts_forced_program),set_int},
{"AUTO_PROGRAM",offsetof(struct ccx_s_options,ts_autoprogram),set_int},
{"STREAM",offsetof(struct ccx_s_options,live_stream),set_int},
{"STREAM",offsetof(struct ccx_s_options,live_stream),set_int},
{"START_AT",offsetof(struct ccx_s_options,extraction_start),set_time},
{"END_AT",offsetof(struct ccx_s_options,extraction_end),set_time},
{"INVASTIGATE_PACKET",offsetof(struct ccx_s_options,investigate_packets),set_int},

View File

@@ -25,6 +25,7 @@
#include "dvb_subtitle_decoder.h"
#include "utility.h"
#include "ccx_decoders_common.h"
#include "ocr.h"
#define DVBSUB_PAGE_SEGMENT 0x10
#define DVBSUB_REGION_SEGMENT 0x11
@@ -272,6 +273,9 @@ typedef struct DVBSubContext
int lang_index;
int version;
int time_out;
#ifdef ENABLE_OCR
void *ocr_ctx;
#endif
DVBSubRegion *region_list;
DVBSubCLUT *clut_list;
DVBSubObject *object_list;
@@ -429,6 +433,14 @@ void* dvbsub_init_decoder(struct dvb_config* cfg)
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;
@@ -1425,6 +1437,7 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
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;
@@ -1440,22 +1453,27 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
if (region && region->dirty)
sub->nb_data++;
}
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;
if( sub->nb_data <= 0 )
{
return 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)
@@ -1495,6 +1513,11 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
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++;
}
@@ -1523,12 +1546,12 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
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;
}
@@ -1547,7 +1570,7 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
if (p_end - p < segment_length)
{
mprint("incomplete or broken packet");
mprint("incomplete or broken packet\n");
return -1;
}

View File

@@ -18,7 +18,7 @@
#define MAX_LANGUAGE_PER_DESC 5
#include "ccextractor.h"
#include "lib_ccx.h"
#ifdef __cplusplus
extern "C"
{
@@ -76,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,4 +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;
@@ -19,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, struct cc_subtitle *sub);
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, struct cc_subtitle *sub);
static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub);
static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub);
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 , struct cc_subtitle *sub);
static int extension_and_user_data(struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
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,struct cc_subtitle *sub)
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;
@@ -47,7 +48,7 @@ LLONG process_m2v (unsigned char *data, LLONG length,struct cc_subtitle *sub)
// Process data. The return value is ignored as esstream.pos holds
// the information how far the parsing progressed.
es_video_sequence(&esstream, sub);
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
@@ -184,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, struct cc_subtitle *sub)
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.
@@ -259,7 +260,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
if (!in_pic_data && startcode == 0xB3)
{
if (!read_seq_info(esstream))
if (!read_seq_info(ctx, esstream))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -271,7 +272,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
if (!in_pic_data && startcode == 0xB8)
{
if (!read_gop_info(esstream,sub))
if (!read_gop_info(ctx, esstream,sub))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -283,7 +284,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
if (!in_pic_data && startcode == 0x00)
{
if (!read_pic_info(esstream, sub))
if (!read_pic_info(ctx, esstream, sub))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -299,7 +300,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
// 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, sub))
if (!read_eau_info(ctx, esstream, saw_seqgoppic-1, sub))
{
if (esstream->error)
no_bitstream_error = 0;
@@ -344,7 +345,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
// 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");
@@ -357,7 +358,7 @@ static int read_seq_info(struct bitstream *esstream)
// 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.
@@ -381,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");
@@ -397,10 +398,10 @@ static int sequence_header(struct bitstream *esstream)
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);
@@ -424,7 +425,7 @@ 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 &&
frame_rate>0 && frame_rate<9 &&
@@ -437,7 +438,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],
@@ -454,8 +455,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",
@@ -526,7 +527,7 @@ 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, struct cc_subtitle *sub)
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");
@@ -539,7 +540,7 @@ static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub)
// after getting more.
unsigned char *gop_info_start = esstream->pos;
gop_header(esstream, sub);
gop_header(ctx, esstream, sub);
//extension_and_user_data(esstream);
if (esstream->error)
@@ -560,7 +561,7 @@ static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub)
// 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, struct cc_subtitle *sub)
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
dbg_print(CCX_DMT_VERBOSE, "GOP header\n");
@@ -593,7 +594,7 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
// Flush buffered cc blocks before doing the housekeeping
if (has_ccdata_buffered)
{
process_hdcc(sub);
process_hdcc(ctx, sub);
}
// Last GOPs pulldown frames
@@ -611,19 +612,19 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
// 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));
}
@@ -656,9 +657,9 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
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)
@@ -697,7 +698,7 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
// 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, struct cc_subtitle *sub)
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");
@@ -728,18 +729,18 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
// 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(sub);
process_hdcc(ctx, sub);
}
anchor_hdcc(temporal_reference);
// }
}
}
current_tref = temporal_reference;
@@ -757,7 +758,7 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
(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()));
@@ -771,16 +772,16 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
// 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
{
@@ -795,39 +796,39 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
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");
@@ -944,7 +945,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, struct cc_subtitle *sub)
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");
@@ -958,7 +959,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype, struct cc_subti
// 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, sub) )
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");
@@ -977,7 +978,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype, struct cc_subti
// 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, struct cc_subtitle *sub)
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);
@@ -1001,7 +1002,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype, struc
// 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)
{
@@ -1029,7 +1030,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype, struc
{
struct bitstream ustream;
init_bitstream(&ustream, dstart, esstream->pos);
user_data(&ustream, udtype, sub);
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, struct cc_subtitle *sub)
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
@@ -23,14 +25,14 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
}
// 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.
// CFS: Seen in Stick_VHS.mpg.
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
}
@@ -38,7 +40,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
// <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, struct cc_subtitle *sub)
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, struct cc_subtitle *sub)
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, sub);
do_cb(dec_ctx, data, sub);
rcbcount++;
}
else
@@ -118,12 +120,12 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
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, sub);
do_cb(dec_ctx, data, sub);
ecbcount++;
}
else
@@ -144,7 +146,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
{
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);
@@ -192,7 +194,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
}
}
cc_data[cc_count*3]=0xFF;
store_hdcc(cc_data, cc_count, current_tref, fts_now, sub);
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, struct cc_subtitle *sub)
}
// 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, sub);
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, sub);
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"
@@ -264,7 +266,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
// 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, sub);
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, struct cc_subtitle *sub)
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, struct cc_subtitle *sub)
dishdata[cc_count*3] = 0xFF; // Set end marker
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
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, struct cc_subtitle *sub)
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, struct cc_subtitle *sub)
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, sub);
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, struct cc_subtitle *sub)
// 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, struct cc_subtitle *sub)
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, sub);
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, struct cc_subtitle *sub)
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, struct cc_subtitle *sub)
data[0]=0x04; // Field 1
data[1]=read_u8(ustream);
data[2]=read_u8(ustream);
do_cb(data, sub);
do_cb(dec_ctx, data, sub);
// This is probably incomplete!
}
else

View File

@@ -13,7 +13,7 @@
#include <libavutil/log.h>
#include <libavutil/error.h>
#include "ccextractor.h"
#include "lib_ccx.h"
struct ffmpeg_ctx
{
AVFormatContext *ifmt;
@@ -74,7 +74,7 @@ void *init_ffmpeg(char *path)
av_log_set_callback(log_cb);
ctx = av_malloc(sizeof(*ctx));
ctx = av_mallocz(sizeof(*ctx));
if(!ctx)
{
av_log(NULL,AV_LOG_ERROR,"Not enough memory\n");
@@ -126,7 +126,7 @@ fail:
* @param maxlen length of buffer, where data will be copied
* @return number of bytes recieved as data
*/
int ff_get_ccframe(void *arg,char*data,int maxlen)
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen)
{
struct ffmpeg_ctx *ctx = arg;
int len = 0;

View File

@@ -19,5 +19,5 @@ void *init_ffmpeg(char *path);
* @param maxlen length of buffer, where data will be copied
* @return number of bytes recieved as data
*/
int ff_get_ccframe(void *arg,char*data,int maxlen);
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen);
#endif

View File

@@ -1,4 +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);
@@ -22,22 +23,22 @@ LLONG getfilesize (int in)
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)
@@ -47,51 +48,53 @@ 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;
}
/* 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();
}
}
@@ -100,118 +103,120 @@ void close_input_file (void)
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;
}
infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
return 1;
if(infd < 0)
if(ctx->infd < 0)
fatal (CCX_COMMON_EXIT_BUG_BUG, "socket() failed.");
}
if (ccx_options.input_source==CCX_DS_TCP)
{
if (infd != -1)
if (ctx->infd != -1)
{
if (ccx_options.print_file_reports)
print_file_report();
print_file_report(ctx);
return 0;
}
infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
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 (CCX_COMMON_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
}
@@ -219,20 +224,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)
@@ -241,17 +246,17 @@ void buffered_seek (int offset)
if (filebuffer_pos<0)
{
// We got into the start buffer (hopefully)
if (startbytes_pos+filebuffer_pos < 0)
if (ctx->startbytes_pos+filebuffer_pos < 0)
{
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();
}
}
@@ -260,7 +265,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;
@@ -273,7 +278,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);
}
@@ -282,7 +287,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);
@@ -295,7 +300,7 @@ 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;
}
@@ -306,33 +311,33 @@ void return_to_buffer (unsigned char *buffer, unsigned int 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
@@ -341,7 +346,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;
@@ -349,10 +354,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)
@@ -372,28 +377,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
i = recvfrom(infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,NULL,NULL);
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;
@@ -403,27 +408,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");
@@ -440,13 +445,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)
@@ -456,7 +461,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,4 +1,5 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#ifdef _WIN32
#include <io.h>
#else
@@ -25,7 +26,7 @@ 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
// Remember if the last header was valid. Used to suppress too much output
@@ -36,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 (struct cc_subtitle *sub);
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;
@@ -52,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;
@@ -72,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 )
{
@@ -93,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;
@@ -104,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;
@@ -122,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;
@@ -136,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;
@@ -144,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
@@ -182,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;
@@ -214,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;
}
@@ -233,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);
@@ -243,17 +242,17 @@ 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);
@@ -262,12 +261,12 @@ LLONG general_getmoredata(void)
#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;
@@ -275,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,':');
@@ -286,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();
@@ -295,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;
@@ -322,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;
@@ -331,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();
}
}
@@ -378,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;
}
@@ -399,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();
}
}
@@ -418,16 +417,16 @@ void processhex (char *filename)
}
free (bytes);
}
fclose(fr);
fclose(fr);
}
#endif
// Raw file process
void raw_loop (void *enc_ctx)
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
@@ -441,12 +440,12 @@ void raw_loop (void *enc_ctx)
{
inbuf=0;
got=general_getmoredata();
got = general_getmoredata(ctx);
if (got == 0) // Shortcircuit if we got nothing to process
break;
processed=process_raw(&dec_sub);
processed=process_raw(ctx, &dec_sub);
if (dec_sub.got_output)
{
encode_sub(enc_ctx,&dec_sub);
@@ -462,10 +461,10 @@ void raw_loop (void *enc_ctx)
(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);
@@ -473,79 +472,85 @@ void raw_loop (void *enc_ctx)
/* 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 ( struct cc_subtitle *sub)
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, sub);
}
}
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 (struct cc_subtitle *sub)
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,sub);
do_cb(dec_ctx, data, sub);
}
}
return inbuf;
}
void general_loop(void *enc_ctx)
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;
inbuf = 0; // No data yet
end_of_file = 0;
current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
memset(&dec_sub, 0,sizeof(dec_sub));
while (!end_of_file && !processed_enough)
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;
@@ -553,35 +558,35 @@ void general_loop(void *enc_ctx)
// 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(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)
@@ -596,25 +601,25 @@ void general_loop(void *enc_ctx)
if (ccx_options.hauppauge_mode)
{
got = process_raw_with_field(&dec_sub);
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)
{
dvbsub_decode(cxx_dvb_context, buffer + 2, inbuf, &dec_sub);
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,&dec_sub);
}
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)
{
@@ -656,18 +661,18 @@ void general_loop(void *enc_ctx)
(unsigned) (current_pts));
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
got = process_raw(&dec_sub);
got = process_raw(ctx, &dec_sub);
}
else if (ccx_bufferdatatype == CCX_H264) // H.264 data from TS file
{
got = process_avc(buffer, inbuf,&dec_sub);
got = process_avc(ctx, ctx->buffer, inbuf,&dec_sub);
}
else
fatal(CCX_COMMON_EXIT_BUG_BUG, "Unknown data type!");
if (got>inbuf)
{
mprint ("BUG BUG\n");
mprint ("BUG BUG\n");
}
pos+=got;
@@ -675,25 +680,25 @@ void general_loop(void *enc_ctx)
{
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;
}
}
}
@@ -706,13 +711,13 @@ void general_loop(void *enc_ctx)
}
// Flush remaining HD captions
if (has_ccdata_buffered)
process_hdcc(&dec_sub);
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);
@@ -722,11 +727,13 @@ void general_loop(void *enc_ctx)
}
// Raw caption with FTS file process
void rcwt_loop(void *enc_ctx)
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
@@ -735,15 +742,15 @@ void rcwt_loop(void *enc_ctx)
// 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)
{
@@ -759,7 +766,7 @@ void rcwt_loop(void *enc_ctx)
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
{
@@ -768,7 +775,7 @@ void rcwt_loop(void *enc_ctx)
if (parsebuf[6] == 0 && parsebuf[7] == 2)
{
tlt_read_rcwt();
tlt_read_rcwt(ctx);
return;
}
@@ -782,8 +789,8 @@ void rcwt_loop(void *enc_ctx)
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)
@@ -809,8 +816,8 @@ void rcwt_loop(void *enc_ctx)
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)
{
@@ -832,7 +839,7 @@ void rcwt_loop(void *enc_ctx)
for (int j=0; j<cbcount*3; j=j+3)
{
do_cb(parsebuf+j, &dec_sub);
do_cb(dec_ctx, parsebuf+j, &dec_sub);
}
}
if (dec_sub.got_output)

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

@@ -0,0 +1,125 @@
#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->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);
}
dinit_ts(lctx);
dinit_cc_decode(&lctx->dec_ctx);
freep(&lctx->buffer);
freep(&lctx->pesheaderbuf);
freep(&lctx->freport.data_from_608);
freep(ctx);
}

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

@@ -0,0 +1,422 @@
#ifndef CCX_CCEXTRACTOR_H
#define CCX_CCEXTRACTOR_H
#define VERSION "0.75"
// 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;
};
/* 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 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 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);
// 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

View File

@@ -1,7 +1,8 @@
/* This code comes from MythTV.
/* This code comes from MythTV.
For now, integration with ccextractor is a quick hack. It could get better with time. */
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_decoders_608.h"
#ifdef _WIN32
#include <io.h>
@@ -287,57 +288,57 @@ typedef struct AVPacket
static AVPacket av;
int get_be16()
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 (a_p);
past++;
buffered_read_byte (b_p);
past++;
buffered_read_byte (ctx, a_p);
ctx->past++;
buffered_read_byte (ctx, b_p);
ctx->past++;
return (a<<8) | b;
}
int get_byte ()
int get_byte (struct lib_ccx_ctx *ctx)
{
unsigned char b;
unsigned char *b_p = &b;
buffered_read_byte(b_p);
buffered_read_byte(ctx, b_p);
if (result==1)
{
past++;
ctx->past++;
return b;
}
else
return 0;
}
unsigned int get_be32()
unsigned int get_be32(struct lib_ccx_ctx *ctx)
{
unsigned int val;
val = get_be16() << 16;
val |= get_be16();
val = get_be16(ctx) << 16;
val |= get_be16(ctx);
return val;
}
static LLONG get_pts(int c)
static LLONG get_pts(struct lib_ccx_ctx *ctx, int c)
{
LLONG pts;
int val;
if (c < 0)
c = get_byte();
c = get_byte(ctx);
pts = (LLONG) ((c >> 1) & 0x07) << 30;
val = get_be16();
val = get_be16(ctx);
pts |= (LLONG) (val >> 1) << 15;
val = get_be16();
val = get_be16(ctx);
pts |= (LLONG) (val >> 1);
return pts;
}
static int find_next_start_code(int *size_ptr,
static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
unsigned int *header_state)
{
unsigned int state, v;
@@ -349,10 +350,10 @@ static int find_next_start_code(int *size_ptr,
{
unsigned char cx;
unsigned char *cx_p = &cx;
buffered_read_byte (cx_p);
buffered_read_byte (ctx, cx_p);
if (result!=1)
break;
past++;
ctx->past++;
v = cx;
n--;
if (state == 0x000001) {
@@ -369,45 +370,45 @@ found:
return val;
}
void url_fskip (int length)
void url_fskip (struct lib_ccx_ctx *ctx, int length)
{
buffered_seek (length);
past+=length;
buffered_seek (ctx, length);
ctx->past+=length;
}
static long mpegps_psm_parse(void)
static long mpegps_psm_parse(struct lib_ccx_ctx *ctx)
{
int psm_length, ps_info_length, es_map_length;
psm_length = get_be16();
get_byte();
get_byte();
ps_info_length = get_be16();
psm_length = get_be16(ctx);
get_byte(ctx);
get_byte(ctx);
ps_info_length = get_be16(ctx);
/* skip program_stream_info */
url_fskip(ps_info_length);
es_map_length = get_be16();
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();
unsigned char es_id =(unsigned char) get_byte();
unsigned int es_info_length = get_be16();
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(es_info_length);
url_fskip(ctx, es_info_length);
es_map_length -= 4 + es_info_length;
}
get_be32(); /* crc32 */
get_be32(ctx); /* crc32 */
return 2 + psm_length;
}
static int mpegps_read_pes_header(int *pstart_code,
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;
@@ -415,7 +416,7 @@ redo:
/* next start code (should be immediately after) */
header_state = 0xff;
size = MAX_SYNC_SIZE;
startcode = find_next_start_code(&size, &header_state);
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;
@@ -427,14 +428,14 @@ redo:
startcode == PRIVATE_STREAM_2)
{
/* skip them */
len = get_be16();
// url_fskip(len);
len = get_be16(ctx);
// url_fskip(ctx, len);
goto redo;
}
position_sanity_check();
if (startcode == PROGRAM_STREAM_MAP)
{
mpegps_psm_parse();
mpegps_psm_parse(ctx);
goto redo;
}
@@ -444,7 +445,7 @@ redo:
(startcode == 0x1bd)))
goto redo;
len = get_be16();
len = get_be16(ctx);
pts = AV_NOPTS_VALUE;
dts = AV_NOPTS_VALUE;
position_sanity_check();
@@ -452,7 +453,7 @@ redo:
for(;;) {
if (len < 1)
goto redo;
c = get_byte();
c = get_byte(ctx);
len--;
/* XXX: for mpeg1, should test only bit 7 */
if (c != 0xff)
@@ -463,21 +464,21 @@ redo:
/* buffer scale & size */
if (len < 2)
goto redo;
get_byte();
c = get_byte();
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( c);
dts = pts = get_pts(ctx, c);
len -= 4;
} else if ((c & 0xf0) == 0x30) {
if (len < 9)
goto redo;
pts = get_pts(c);
dts = get_pts(-1);
pts = get_pts(ctx, c);
dts = get_pts(ctx, -1);
len -= 9;
} else if ((c & 0xc0) == 0x80) {
/* mpeg 2 PES */
@@ -487,20 +488,20 @@ redo:
goto redo;
}
#endif
flags = get_byte();
header_len = get_byte();
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(-1);
dts = pts = get_pts(ctx, -1);
if (header_len < 5)
goto redo;
header_len -= 5;
len -= 5;
} if ((flags & 0xc0) == 0xc0) {
pts = get_pts( -1);
dts = get_pts( -1);
pts = get_pts(ctx, -1);
dts = get_pts(ctx, -1);
if (header_len < 10)
goto redo;
header_len -= 10;
@@ -508,7 +509,7 @@ redo:
}
len -= header_len;
while (header_len > 0) {
get_byte();
get_byte(ctx);
header_len--;
}
}
@@ -519,15 +520,15 @@ redo:
{
if (len < 1)
goto redo;
startcode = get_byte();
startcode = get_byte(ctx);
len--;
if (startcode >= 0x80 && startcode <= 0xbf) {
/* audio: skip header */
if (len < 3)
goto redo;
get_byte();
get_byte();
get_byte();
get_byte(ctx);
get_byte(ctx);
get_byte(ctx);
len -= 3;
}
}
@@ -550,9 +551,10 @@ static int cc608_good_parity(const int *parity_table, unsigned int data)
}
void ProcessVBIDataPacket(struct cc_subtitle *sub)
{
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)
{
@@ -561,6 +563,7 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
}
LLONG linemask = 0;
dec_ctx = ctx->dec_ctx;
// unsigned long long utc = lastccptsu;
// [i]tv0 means there is a linemask
@@ -614,7 +617,7 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
ccdata[0]=0x04; // Field 1
ccdata[1]=meat[1];
ccdata[2]=meat[2];
do_cb(ccdata,sub);
do_cb(dec_ctx, ccdata, sub);
// processed_ccblocks++; // Not sure this is accurate
}
else
@@ -622,7 +625,7 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
ccdata[0]=0x05; // Field 1
ccdata[1]=meat[1];
ccdata[2]=meat[2];
do_cb(ccdata, sub);
do_cb(dec_ctx, ccdata, sub);
}
}
// utc += 33367;
@@ -643,13 +646,13 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
// lastccptsu = utc;
}
static int mpegps_read_packet(void)
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(&startcode, &pts, &dts);
len = mpegps_read_pes_header(ctx, &startcode, &pts, &dts);
if (len < 0)
return len;
position_sanity_check();
@@ -694,11 +697,11 @@ redo:
{
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
unsigned char buf[8];
buffered_read (buf,8);
past+=8;
buffered_read (ctx, buf,8);
ctx->past+=8;
// get_buffer(&s->pb, buf, 8);
buffered_seek (-8);
past-=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
@@ -725,7 +728,7 @@ redo:
} else {
skip:
// skip packet
url_fskip(len);
url_fskip(ctx, len);
goto redo;
}
// no stream found: add a new stream
@@ -752,9 +755,9 @@ goto skip; */
// audio data
if (len <= 3)
goto skip;
get_byte(); // emphasis (1), muse(1), reserved(1), frame number(5)
get_byte(); // quant (2), freq(2), reserved(1), channels(3)
get_byte(); // dynamic range control (0x80 = off)
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];
@@ -776,8 +779,8 @@ goto skip; */
}
av.codec_id=codec_id;
av.type=type;
buffered_read (av.data,av.size);
past+=av.size;
buffered_read (ctx, av.data,av.size);
ctx->past+=av.size;
position_sanity_check();
// LSEEK (fh,pkt->size,SEEK_CUR);
av.pts = pts;
@@ -823,15 +826,17 @@ void build_parity_table (void)
cc608_build_parity_table(cc608_parity_table);
}
void myth_loop(void *enc_ctx)
{
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
{
int rc;
int has_vbi=0;
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");
@@ -843,7 +848,7 @@ void myth_loop(void *enc_ctx)
saved=0;
memset(&dec_sub, 0, sizeof(dec_sub));
while (!processed_enough && (rc=mpegps_read_packet ())==0)
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)
@@ -852,9 +857,9 @@ void myth_loop(void *enc_ctx)
{
mprint ("\rDetected VBI data, disabling user-data packet analysis (not needed).\n");
has_vbi=1;
}
}
//fts_now=LLONG((processed_ccblocks*1000)/29.97);
ProcessVBIDataPacket(&dec_sub);
ProcessVBIDataPacket(ctx, &dec_sub);
}
/* This needs a lot more testing */
if (av.codec_id==CODEC_ID_MPEG2VIDEO && av.type==CODEC_TYPE_VIDEO )
@@ -865,7 +870,7 @@ void myth_loop(void *enc_ctx)
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");
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
}
if (av.pts!=AV_NOPTS_VALUE)
{
@@ -874,33 +879,33 @@ void myth_loop(void *enc_ctx)
pts_set=1;
}
memcpy (desp+saved,av.data,av.size);
LLONG used = process_m2v(desp, length, &dec_sub);
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 (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 > 0 )
if (ctx->total_inputsize > 0 )
{
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)
{
int cur_sec = (int) (get_fts() / 1000);
activity_progress (progress, cur_sec/60, cur_sec%60);
fflush (stdout);
last_reported_progress = progress;
ctx->last_reported_progress = progress;
}
}
}

View File

@@ -1,4 +1,4 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "networking.h"
#include <stdio.h>
@@ -124,7 +124,7 @@ void net_send_header(const unsigned char *data, size_t len)
if (ERROR == ok)
{
printf("Internal server error\n");
printf("Internal server error\n");
return;
}
@@ -329,7 +329,7 @@ int ask_passwd(int sd)
{
mprint("Too many connections to the server, try later\n");
return -1;
}
}
else if (ERROR == ok)
{
mprint("Internal server error\n");
@@ -581,7 +581,7 @@ int tcp_bind(const char *port, int *family)
if (bind(sockfd, p->ai_addr, p->ai_addrlen) < 0)
{
#if _WIN32
wprintf(L"bind() eror: %ld\n", WSAGetLastError());
wprintf(L"bind() error: %ld\n", WSAGetLastError());
closesocket(sockfd);
#else
mprint("bind() error: %s\n", strerror(errno));

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,17 +1,20 @@
#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)
{
@@ -29,7 +32,7 @@ void writedata(const unsigned char *data, int length, ccx_decoder_608_context *c
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 ||
@@ -40,10 +43,10 @@ void writedata(const unsigned char *data, int length, ccx_decoder_608_context *c
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,50 @@ 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,
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;
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, sub);
}
if (length2)
{
if (length1 && ccx_options.extract != 2)
{
if (ccx_options.extract!=1)
writedata(data2, length2, &context_cc608_field_2, sub);
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, 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,14 +185,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;
@@ -193,7 +202,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;
@@ -228,14 +237,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;

View File

@@ -1,7 +1,8 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "utility.h"
static int inputfile_capacity=0;
static int inputfile_capacity=0;
static const char *DEF_VAL_STARTCREDITSNOTBEFORE="0";
static const char *DEF_VAL_STARTCREDITSNOTAFTER="5:00"; // To catch the theme after the teaser in TV shows
@@ -54,7 +55,6 @@ int stringztoms (const char *s, struct ccx_boundary_time *bt)
bt->time_in_ms=secs*1000;
return 0;
}
int process_cap_file (char *filename)
{
int ret = 0;
@@ -107,16 +107,16 @@ int isanumber (char *s)
return 1;
}
int parsedelay (char *par)
int parsedelay (struct ccx_s_options *opt, char *par)
{
int sign=0;
int sign=0;
char *c=par;
while (*c)
{
if (*c=='-' || *c=='+')
{
if (c!=par) // Sign only at the beginning
return 1;
return 1;
if (*c=='-')
sign=1;
}
@@ -124,37 +124,37 @@ int parsedelay (char *par)
{
if (!isdigit (*c))
return 1;
subs_delay=subs_delay*10 + (*c-'0');
opt->subs_delay = opt->subs_delay*10 + (*c-'0');
}
c++;
}
if (sign)
subs_delay=-subs_delay;
opt->subs_delay =- opt->subs_delay;
return 0;
}
int append_file_to_queue (char *filename)
int append_file_to_queue (struct ccx_s_options *opt,char *filename)
{
char *c=(char *) malloc (strlen (filename)+1);
if (c==NULL)
return -1;
return -1;
strcpy (c,filename);
if (inputfile_capacity<=num_input_files)
if (inputfile_capacity<=opt->num_input_files)
{
inputfile_capacity+=10;
inputfile=(char **) realloc (inputfile,sizeof (char *) * inputfile_capacity);
if (inputfile==NULL)
opt->inputfile=(char **) realloc (opt->inputfile,sizeof (char *) * inputfile_capacity);
if (opt->inputfile==NULL)
{
free(c);
return -1;
}
}
inputfile[num_input_files]=c;
num_input_files++;
opt->inputfile[opt->num_input_files]=c;
opt->num_input_files++;
return 0;
}
int add_file_sequence (char *filename)
int add_file_sequence (struct ccx_s_options *opt, char *filename)
{
int m,n;
n=strlen (filename)-1;
@@ -162,7 +162,7 @@ int add_file_sequence (char *filename)
while (n>=0 && !isdigit (filename[n]))
n--;
if (n==-1) // None. No expansion needed
return append_file_to_queue(filename);
return append_file_to_queue(opt, filename);
m=n;
while (m>=0 && isdigit (filename[m]))
m--;
@@ -187,7 +187,7 @@ int add_file_sequence (char *filename)
if (f==NULL) // Doesn't exist or we can't read it. We're done
break;
fclose (f);
if (append_file_to_queue (filename)) // Memory panic
if (append_file_to_queue (opt, filename)) // Memory panic
{
free(num);
free(temp);
@@ -218,7 +218,7 @@ void set_output_format (const char *format)
if (strcmp (format,"srt")==0)
ccx_options.write_format=CCX_OF_SRT;
else if (strcmp (format,"sami")==0 || strcmp (format,"smi")==0)
else if (strcmp (format,"sami")==0 || strcmp (format,"smi")==0)
ccx_options.write_format=CCX_OF_SAMI;
else if (strcmp (format,"transcript")==0 || strcmp (format,"txt")==0)
{
@@ -230,12 +230,14 @@ void set_output_format (const char *format)
if (ccx_options.date_format==ODF_NONE)
ccx_options.date_format=ODF_HHMMSSMS;
// Sets the right things so that timestamps and the mode are printed.
ccx_options.transcript_settings.showStartTime = 1;
ccx_options.transcript_settings.showEndTime = 1;
ccx_options.transcript_settings.showCC = 0;
ccx_options.transcript_settings.showMode = 1;
if (!ccx_options.transcript_settings.isFinal){
ccx_options.transcript_settings.showStartTime = 1;
ccx_options.transcript_settings.showEndTime = 1;
ccx_options.transcript_settings.showCC = 0;
ccx_options.transcript_settings.showMode = 1;
}
}
else if (strcmp (format,"report")==0)
else if (strcmp (format,"report")==0)
{
ccx_options.write_format=CCX_OF_NULL;
ccx_options.messages_target=0;
@@ -258,7 +260,7 @@ void set_output_format (const char *format)
fatal (EXIT_MALFORMED_PARAMETER, "Unknown output file format: %s\n", format);
}
void set_input_format (const char *format)
void set_input_format (struct ccx_s_options *opt, const char *format)
{
if (ccx_options.input_source == CCX_DS_TCP && strcmp(format, "bin")!=0)
{
@@ -269,24 +271,24 @@ void set_input_format (const char *format)
while (*format=='-')
format++;
if (strcmp (format,"es")==0) // Does this actually do anything?
auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
opt->auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
else if (strcmp (format,"ts")==0)
auto_stream = CCX_SM_TRANSPORT;
opt->auto_stream = CCX_SM_TRANSPORT;
else if (strcmp (format,"ps")==0 || strcmp (format,"nots")==0)
auto_stream = CCX_SM_PROGRAM;
opt->auto_stream = CCX_SM_PROGRAM;
else if (strcmp (format,"asf")==0 || strcmp (format,"dvr-ms")==0)
auto_stream = CCX_SM_ASF;
opt->auto_stream = CCX_SM_ASF;
else if (strcmp (format,"wtv")==0)
auto_stream = CCX_SM_WTV;
opt->auto_stream = CCX_SM_WTV;
else if (strcmp (format,"raw")==0)
auto_stream = CCX_SM_MCPOODLESRAW;
opt->auto_stream = CCX_SM_MCPOODLESRAW;
else if (strcmp (format,"bin")==0)
auto_stream = CCX_SM_RCWT;
opt->auto_stream = CCX_SM_RCWT;
else if (strcmp (format,"mp4")==0)
auto_stream = CCX_SM_MP4;
opt->auto_stream = CCX_SM_MP4;
#ifdef WTV_DEBUG
else if (strcmp (format,"hex")==0)
auto_stream = CCX_SM_HEX_DUMP;
opt->auto_stream = CCX_SM_HEX_DUMP;
#endif
else
fatal (EXIT_MALFORMED_PARAMETER, "Unknown input file format: %s\n", format);
@@ -346,7 +348,7 @@ void usage (void)
mprint (" -1, -2, -12: Output Field 1 data, Field 2 data, or both\n");
mprint (" (DEFAULT is -1)\n");
mprint (" -cc2: When in srt/sami mode, process captions in channel 2\n");
mprint (" instead channel 1.\n");
mprint (" instead of channel 1.\n");
mprint ("-svc --service N,N...: Enabled CEA-708 captions processing for the listed\n");
mprint (" services. The parameter is a command delimited list\n");
mprint (" of services numbers, such as \"1,2\" to process the\n");
@@ -440,8 +442,8 @@ void usage (void)
mprint (" software to convert *.wtv to *.dvr-ms. For analog NTSC\n");
mprint (" recordings the CC information is marked as digital\n");
mprint (" captions. Use this switch only when needed.\n");
mprint (" -wtvmpeg2: Read the captions from the MPEG2 video stream rather\n");
mprint (" than the captions stream in WTV files\n");
mprint (" -wtvmpeg2: Read the captions from the MPEG2 video stream rather\n");
mprint (" than the captions stream in WTV files\n");
mprint (" -pn --program-number: In TS mode, specifically select a program to process.\n");
mprint (" Not needed if the TS only has one. If this parameter\n");
mprint (" is not specified and CCExtractor detects more than one\n");
@@ -475,6 +477,13 @@ void usage (void)
mprint (" affects Teletext in timed transcript with -datets.\n");
mprint ("\n");
mprint ("Options that affect what kind of output will be produced:\n");
mprint(" -bom: Append a BOM (Byte Order Mark) to output files.");
mprint(" Note that most text processing tools in linux will not");
mprint(" like BOM.");
mprint(" This is the default in Windows builds.");
mprint(" -nobom: Do not append a BOM (Byte Order Mark) to output files.");
mprint(" Note that this may break files when using Windows.");
mprint(" This is the default in non-Windows builds.");
mprint (" -unicode: Encode subtitles in Unicode instead of Latin-1.\n");
mprint (" -utf8: Encode subtitles in UTF-8 (no longer needed.\n");
mprint (" because UTF-8 is now the default).\n");
@@ -732,7 +741,7 @@ void parse_708services (char *s)
while (*c && !isdigit (*c))
c++;
if (!*c) // We're done
break;
break;
e=c;
while (isdigit (*e))
e++;
@@ -790,17 +799,17 @@ void init_option (struct ccx_s_options *option)
option->ts_forced_program_selected = 1;
}
void parse_parameters (int argc, char *argv[])
void parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
{
char *cea708_service_list=NULL; // List CEA-708 services
// Sensible default values for credits
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &ccx_options.startcreditsnotbefore);
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &ccx_options.startcreditsnotafter);
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &ccx_options.startcreditsforatleast);
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &ccx_options.startcreditsforatmost);
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &ccx_options.endcreditsforatleast);
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &ccx_options.endcreditsforatmost);
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &opt->startcreditsnotbefore);
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &opt->startcreditsnotafter);
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &opt->startcreditsforatleast);
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &opt->startcreditsforatmost);
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &opt->endcreditsforatleast);
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &opt->endcreditsforatmost);
// Parse parameters
for (int i=1; i<argc; i++)
@@ -808,8 +817,8 @@ void parse_parameters (int argc, char *argv[])
if (strcmp (argv[i], "-")==0 || strcmp(argv[i], "-stdin") == 0)
{
ccx_options.input_source=CCX_DS_STDIN;
ccx_options.live_stream=-1;
opt->input_source=CCX_DS_STDIN;
opt->live_stream=-1;
continue;
}
if (argv[i][0]!='-')
@@ -817,12 +826,12 @@ void parse_parameters (int argc, char *argv[])
int rc;
if (argv[i][strlen (argv[i])-1]!='+')
{
rc=append_file_to_queue (argv[i]);
rc=append_file_to_queue (opt, argv[i]);
}
else
{
argv[i][strlen (argv[i])-1]=0;
rc=add_file_sequence (argv[i]);
rc=add_file_sequence (opt, argv[i]);
}
if (rc)
{
@@ -861,6 +870,14 @@ void parse_parameters (int argc, char *argv[])
ccx_options.nofontcolor=1;
continue;
}
if (strcmp(argv[i], "-bom") == 0){
ccx_options.no_bom = 0;
continue;
}
if (strcmp(argv[i], "-nobom") == 0){
ccx_options.no_bom = 1;
continue;
}
if (strcmp (argv[i],"-nots")==0 ||
strcmp (argv[i],"--notypesetting")==0)
{
@@ -878,12 +895,12 @@ void parse_parameters (int argc, char *argv[])
strcmp (argv[i],"-mp4")==0 ||
strcmp (argv[i],"--dvr-ms")==0 )
{
set_input_format (argv[i]);
set_input_format (opt, argv[i]);
continue;
}
if (strncmp (argv[i],"-in=", 4)==0)
{
set_input_format (argv[i]+4);
set_input_format (opt, argv[i]+4);
continue;
}
@@ -1031,19 +1048,19 @@ void parse_parameters (int argc, char *argv[])
ccx_options.extract = 12;
continue;
}
if (strcmp (argv[i],"-gt")==0 ||
if (strcmp (argv[i],"-gt")==0 ||
strcmp (argv[i],"--goptime")==0)
{
ccx_options.use_gop_as_pts = 1;
continue;
}
if (strcmp (argv[i],"-nogt")==0 ||
if (strcmp (argv[i],"-nogt")==0 ||
strcmp (argv[i],"--nogoptime")==0)
{
ccx_options.use_gop_as_pts = -1; // Don't use even if we would want to
continue;
}
if (strcmp (argv[i],"-fp")==0 ||
if (strcmp (argv[i],"-fp")==0 ||
strcmp (argv[i],"--fixpadding")==0)
{
ccx_options.fix_padding = 1;
@@ -1054,7 +1071,7 @@ void parse_parameters (int argc, char *argv[])
MPEG_CLOCK_FREQ=90090;
continue;
}
if (strcmp (argv[i],"-noru")==0 ||
if (strcmp (argv[i],"-noru")==0 ||
strcmp (argv[i],"--norollup")==0)
{
ccx_options.settings_608.no_rollup = 1;
@@ -1108,7 +1125,7 @@ void parse_parameters (int argc, char *argv[])
if (strcmp (argv[i],"--program-number")==0 ||
strcmp (argv[i],"-pn")==0)
{
if (i==argc-1 // Means no following argument
if (i==argc-1 // Means no following argument
|| !isanumber (argv[i+1])) // Means is not a number
ccx_options.ts_forced_program = (unsigned)-1; // Autodetect
else
@@ -1127,7 +1144,7 @@ void parse_parameters (int argc, char *argv[])
if (strcmp (argv[i],"--stream")==0 ||
strcmp (argv[i],"-s")==0)
{
if (i==argc-1 // Means no following argument
if (i==argc-1 // Means no following argument
|| !isanumber (argv[i+1])) // Means is not a number
ccx_options.live_stream=-1; // Live stream without timeout
else
@@ -1152,14 +1169,14 @@ void parse_parameters (int argc, char *argv[])
}
if (strcmp (argv[i],"-delay")==0 && i<argc-1)
{
if (parsedelay (argv[i+1]))
if (parsedelay (opt, argv[i+1]))
{
fatal (EXIT_MALFORMED_PARAMETER, "-delay only accept integers (such as -300 or 300)\n");
}
i++;
continue;
}
if ((strcmp (argv[i],"-scr")==0 ||
if ((strcmp (argv[i],"-scr")==0 ||
strcmp (argv[i],"--screenfuls")==0) && i<argc-1)
{
ccx_options.settings_608.screens_to_process = atoi_hex(argv[i + 1]);
@@ -1207,7 +1224,7 @@ void parse_parameters (int argc, char *argv[])
{
if (ccx_options.messages_target==1) // Only change this if still stdout. -quiet could set it to 0 for example
ccx_options.messages_target=2; // stderr
cc_to_stdout=1;
opt->cc_to_stdout=1;
continue;
}
if (strcmp (argv[i],"-quiet")==0)
@@ -1227,7 +1244,7 @@ void parse_parameters (int argc, char *argv[])
}
if (strcmp (argv[i],"-deblev")==0)
{
ccx_options.debug_mask |= CCX_DMT_LEVENSHTEIN;
ccx_options.debug_mask |= CCX_DMT_LEVENSHTEIN;
continue;
}
if (strcmp (argv[i],"-levdistmincnt")==0 && i<argc-1)
@@ -1247,7 +1264,7 @@ void parse_parameters (int argc, char *argv[])
ccx_options.debug_mask |= CCX_DMT_708;
continue;
}
if (strcmp (argv[i],"-goppts")==0)
if (strcmp (argv[i],"-goppts")==0)
{
ccx_options.debug_mask |= CCX_DMT_TIME;
continue;
@@ -1259,6 +1276,7 @@ void parse_parameters (int argc, char *argv[])
}
if (strcmp (argv[i],"-xds")==0)
{
// XDS can be set regardless of -UCLA (isFinal) usage.
ccx_options.transcript_settings.xds = 1;
continue;
}
@@ -1372,13 +1390,13 @@ void parse_parameters (int argc, char *argv[])
}
if (strcmp (argv[i],"-o1")==0 && i<argc-1)
{
wbout1.filename=argv[i+1];
opt->wbout1.filename=argv[i+1];
i++;
continue;
}
if (strcmp (argv[i],"-o2")==0 && i<argc-1)
{
wbout2.filename=argv[i+1];
opt->wbout2.filename=argv[i+1];
i++;
continue;
}
@@ -1421,11 +1439,15 @@ void parse_parameters (int argc, char *argv[])
if (strcmp (argv[i],"-UCLA")==0 || strcmp (argv[i],"-ucla")==0)
{
ccx_options.millis_separator='.';
ccx_options.transcript_settings.showStartTime = 1;
ccx_options.transcript_settings.showEndTime = 1;
ccx_options.transcript_settings.showCC = 1;
ccx_options.transcript_settings.showMode = 1;
ccx_options.transcript_settings.relativeTimestamp = 0;
ccx_options.no_bom = 1;
if (!ccx_options.transcript_settings.isFinal){
ccx_options.transcript_settings.showStartTime = 1;
ccx_options.transcript_settings.showEndTime = 1;
ccx_options.transcript_settings.showCC = 1;
ccx_options.transcript_settings.showMode = 1;
ccx_options.transcript_settings.relativeTimestamp = 0;
ccx_options.transcript_settings.isFinal = 1;
}
continue;
}
if (strcmp (argv[i],"-lf")==0 || strcmp (argv[i],"-LF")==0)
@@ -1447,7 +1469,7 @@ void parse_parameters (int argc, char *argv[])
{
uint64_t t = 0;
t = atoi_hex(argv[i + 1]);
if (t <= 0)
if (t <= 0)
{
time_t now = time(NULL);
t = time(&now);
@@ -1485,13 +1507,18 @@ void parse_parameters (int argc, char *argv[])
if (strlen(format) == 7){
if (ccx_options.date_format == ODF_NONE)
ccx_options.date_format = ODF_HHMMSSMS; // Necessary for displaying times, if any would be used.
ccx_options.transcript_settings.showStartTime = format[0]-'0';
ccx_options.transcript_settings.showEndTime = format[1] - '0';
ccx_options.transcript_settings.showMode = format[2] - '0';
ccx_options.transcript_settings.showCC = format[3] - '0';
ccx_options.transcript_settings.relativeTimestamp = format[4] - '0';
ccx_options.transcript_settings.xds = format[5] - '0';
ccx_options.transcript_settings.useColors = format[6] - '0';
if (!ccx_options.transcript_settings.isFinal){
ccx_options.transcript_settings.showStartTime = format[0] - '0';
ccx_options.transcript_settings.showEndTime = format[1] - '0';
ccx_options.transcript_settings.showMode = format[2] - '0';
ccx_options.transcript_settings.showCC = format[3] - '0';
ccx_options.transcript_settings.relativeTimestamp = format[4] - '0';
ccx_options.transcript_settings.xds = format[5] - '0';
ccx_options.transcript_settings.useColors = format[6] - '0';
} else {
// Throw exception
fatal(EXIT_INCOMPATIBLE_PARAMETERS, "customtxt cannot be set after -UCLA is used!");
}
i++;
}
else {
@@ -1565,7 +1592,7 @@ void parse_parameters (int argc, char *argv[])
ccx_options.tcpport = argv[i + 1];
ccx_options.input_source = CCX_DS_TCP;
set_input_format("bin");
set_input_format(opt, "bin");
i++;
continue;
@@ -1591,4 +1618,3 @@ void parse_parameters (int argc, char *argv[])
// Unrecognized switches are silently ignored
}
}

View File

@@ -1,14 +1,15 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
void params_dump(void)
void params_dump(struct lib_ccx_ctx *ctx)
{
// Display parsed parameters
mprint ("Input: ");
switch (ccx_options.input_source)
{
case CCX_DS_FILE:
for (int i=0;i<num_input_files;i++)
mprint ("%s%s",inputfile[i],i==(num_input_files-1)?"":",");
for (int i=0;i<ctx->num_input_files;i++)
mprint ("%s%s",ctx->inputfile[i],i==(ctx->num_input_files-1)?"":",");
break;
case CCX_DS_STDIN:
mprint ("stdin");
@@ -25,10 +26,10 @@ void params_dump(void)
mprint("Network, TCP/%s", ccx_options.tcpport);
break;
}
mprint ("\n");
mprint ("\n");
mprint ("[Extract: %d] ", ccx_options.extract);
mprint ("[Stream mode: ");
switch (auto_stream)
switch (ctx->auto_stream)
{
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
mprint ("Elementary");
@@ -73,7 +74,7 @@ void params_dump(void)
else
mprint ("Auto ]");
mprint (" [Hauppage mode: %s]",ccx_options.hauppauge_mode?"Yes":"No");
mprint (" [Use MythTV code: ");
switch (ccx_options.auto_myth)
{
@@ -113,12 +114,12 @@ void params_dump(void)
mprint ("Auto");
break;
}
mprint ("] ");
mprint ("] ");
mprint ("[Debug: %s] ", (ccx_options.debug_mask & CCX_DMT_VERBOSE) ? "Yes": "No");
mprint ("[Buffer input: %s]\n", ccx_options.buffer_input ? "Yes": "No");
mprint ("[Use pic_order_cnt_lsb for H.264: %s] ", ccx_options.usepicorder ? "Yes": "No");
mprint("[Print CC decoder traces: %s]\n", (ccx_options.debug_mask & CCX_DMT_DECODER_608) ? "Yes" : "No");
mprint ("[Target format: %s] ",extension);
mprint ("[Target format: %s] ",ctx->extension);
mprint ("[Encoding: ");
switch (ccx_options.encoding)
{
@@ -133,7 +134,7 @@ void params_dump(void)
break;
}
mprint ("] ");
mprint ("[Delay: %lld] ",subs_delay);
mprint ("[Delay: %lld] ",ctx->subs_delay);
mprint ("[Trim lines: %s]\n",ccx_options.trim_subs?"Yes":"No");
mprint ("[Add font color data: %s] ", ccx_options.nofontcolor? "No" : "Yes");
@@ -179,40 +180,48 @@ void params_dump(void)
mprint ("%d]\n",tlt_config.page);
else
mprint ("Autodetect]\n");
mprint ("Start credits text: [%s]\n",
mprint ("Start credits text: [%s]\n",
ccx_options.start_credits_text?ccx_options.start_credits_text:"None");
if (ccx_options.start_credits_text)
{
mprint ("Start credits time: Insert between [%ld] and [%ld] seconds\n",
(long) (ccx_options.startcreditsnotbefore.time_in_ms/1000),
(long) (ccx_options.startcreditsnotbefore.time_in_ms/1000),
(long) (ccx_options.startcreditsnotafter.time_in_ms/1000)
);
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
(long) (ccx_options.startcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.startcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.startcreditsforatmost.time_in_ms/1000)
);
}
if (ccx_options.end_credits_text)
{
mprint ("End credits text: [%s]\n",
mprint ("End credits text: [%s]\n",
ccx_options.end_credits_text?ccx_options.end_credits_text:"None");
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
(long) (ccx_options.endcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.endcreditsforatleast.time_in_ms/1000),
(long) (ccx_options.endcreditsforatmost.time_in_ms/1000)
);
}
}
void print_file_report(void)
void print_file_report(struct lib_ccx_ctx *ctx)
{
struct lib_cc_decode *dec_ctx = NULL;
dec_ctx = ctx->dec_ctx;
#define Y_N(cond) ((cond) ? "Yes" : "No")
printf("File: ");
switch (ccx_options.input_source)
{
case CCX_DS_FILE:
printf("%s\n", inputfile[current_file]);
if (ctx->current_file < 0)
{
printf("file is not openened yet\n");
return;
}
printf("%s\n", ctx->inputfile[ctx->current_file]);
break;
case CCX_DS_STDIN:
printf("stdin\n");
@@ -224,12 +233,12 @@ void print_file_report(void)
}
printf("Stream Mode: ");
switch (stream_mode)
switch (ctx->stream_mode)
{
case CCX_SM_TRANSPORT:
printf("Transport Stream\n");
printf("Program Count: %d\n", file_report.program_cnt);
printf("Program Count: %d\n", ctx->freport.program_cnt);
printf("Program Numbers: ");
for (int i = 0; i < pmt_array_length; i++)
@@ -241,28 +250,28 @@ void print_file_report(void)
}
printf("\n");
for (int i = 0; i < 65536; i++)
for (int i = 0; i < 65536; i++)
{
if (PIDs_programs[i] == 0)
if (ctx->PIDs_programs[i] == 0)
continue;
printf("PID: %u, Program: %u, ", i, PIDs_programs[i]->program_number);
printf("PID: %u, Program: %u, ", i, ctx->PIDs_programs[i]->program_number);
int j;
for (j = 0; j < SUB_STREAMS_CNT; j++)
for (j = 0; j < SUB_STREAMS_CNT; j++)
{
if (file_report.dvb_sub_pid[j] == i)
if (ctx->freport.dvb_sub_pid[j] == i)
{
printf("DVB Subtitles\n");
break;
}
if (file_report.tlt_sub_pid[j] == i)
if (ctx->freport.tlt_sub_pid[j] == i)
{
printf("Teletext Subtitles\n");
break;
}
}
if (j == SUB_STREAMS_CNT)
printf("%s\n", desc[PIDs_programs[i]->printable_stream_type]);
printf("%s\n", desc[ctx->PIDs_programs[i]->printable_stream_type]);
}
break;
@@ -277,7 +286,7 @@ void print_file_report(void)
break;
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
printf("Not Found\n");
break;
break;
case CCX_SM_MP4:
printf("MP4\n");
break;
@@ -296,29 +305,29 @@ void print_file_report(void)
break;
}
if (ccx_bufferdatatype == CCX_PES &&
(stream_mode == CCX_SM_TRANSPORT ||
stream_mode == CCX_SM_PROGRAM ||
stream_mode == CCX_SM_ASF ||
stream_mode == CCX_SM_WTV))
if (ccx_bufferdatatype == CCX_PES &&
(ctx->stream_mode == CCX_SM_TRANSPORT ||
ctx->stream_mode == CCX_SM_PROGRAM ||
ctx->stream_mode == CCX_SM_ASF ||
ctx->stream_mode == CCX_SM_WTV))
{
printf("Width: %u\n", file_report.width);
printf("Height: %u\n", file_report.height);
printf("Aspect Ratio: %s\n", aspect_ratio_types[file_report.aspect_ratio]);
printf("Frame Rate: %s\n", framerates_types[file_report.frame_rate]);
printf("Width: %u\n", ctx->freport.width);
printf("Height: %u\n", ctx->freport.height);
printf("Aspect Ratio: %s\n", aspect_ratio_types[ctx->freport.aspect_ratio]);
printf("Frame Rate: %s\n", framerates_types[ctx->freport.frame_rate]);
}
if (file_report.program_cnt > 1)
if (ctx->freport.program_cnt > 1)
printf("//////// Program #%u: ////////\n", TS_program_number);
printf("DVB Subtitles: ");
int j;
for (j = 0; j < SUB_STREAMS_CNT; j++)
for (j = 0; j < SUB_STREAMS_CNT; j++)
{
unsigned pid = file_report.dvb_sub_pid[j];
unsigned pid = ctx->freport.dvb_sub_pid[j];
if (pid == 0)
continue;
if (PIDs_programs[pid]->program_number == TS_program_number)
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
{
printf("Yes\n");
break;
@@ -328,17 +337,17 @@ void print_file_report(void)
printf("No\n");
printf("Teletext: ");
for (j = 0; j < SUB_STREAMS_CNT; j++)
for (j = 0; j < SUB_STREAMS_CNT; j++)
{
unsigned pid = file_report.tlt_sub_pid[j];
unsigned pid = ctx->freport.tlt_sub_pid[j];
if (pid == 0)
continue;
if (PIDs_programs[pid]->program_number == TS_program_number)
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
{
printf("Yes\n");
printf("Pages With Subtitles: ");
for (int i = 0; i < MAX_TLT_PAGES; i++)
for (int i = 0; i < MAX_TLT_PAGES; i++)
{
if (seen_sub_page[i] == 0)
continue;
@@ -352,42 +361,42 @@ void print_file_report(void)
if (j == SUB_STREAMS_CNT)
printf("No\n");
printf("EIA-608: %s\n", Y_N(cc_stats[0] > 0 || cc_stats[1] > 0));
printf("EIA-608: %s\n", Y_N(dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0));
if (cc_stats[0] > 0 || cc_stats[1] > 0)
if (dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0)
{
printf("XDS: %s\n", Y_N(file_report.data_from_608.xds));
printf("XDS: %s\n", Y_N(ctx->freport.data_from_608->xds));
printf("CC1: %s\n", Y_N(file_report.data_from_608.cc_channels[0]));
printf("CC2: %s\n", Y_N(file_report.data_from_608.cc_channels[1]));
printf("CC3: %s\n", Y_N(file_report.data_from_608.cc_channels[2]));
printf("CC4: %s\n", Y_N(file_report.data_from_608.cc_channels[3]));
printf("CC1: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[0]));
printf("CC2: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[1]));
printf("CC3: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[2]));
printf("CC4: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[3]));
}
printf("CEA-708: %s\n", Y_N(cc_stats[2] > 0 || cc_stats[3] > 0));
printf("CEA-708: %s\n", Y_N(dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0));
if (cc_stats[2] > 0 || cc_stats[3] > 0)
if (dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0)
{
printf("Services: ");
for (int i = 0; i < CCX_DECODERS_708_MAX_SERVICES; i++)
for (int i = 0; i < CCX_DECODERS_708_MAX_SERVICES; i++)
{
if (file_report.data_from_708.services[i] == 0)
if (ctx->freport.data_from_708->services[i] == 0)
continue;
printf("%d ", i);
}
printf("\n");
printf("Primary Language Present: %s\n", Y_N(file_report.data_from_708.services[1]));
printf("Primary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[1]));
printf("Secondary Language Present: %s\n", Y_N(file_report.data_from_708.services[2]));
printf("Secondary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[2]));
}
printf("MPEG-4 Timed Text: %s\n", Y_N(file_report.mp4_cc_track_cnt));
if (file_report.mp4_cc_track_cnt) {
printf("MPEG-4 Timed Text tracks count: %d\n", file_report.mp4_cc_track_cnt);
printf("MPEG-4 Timed Text: %s\n", Y_N(ctx->freport.mp4_cc_track_cnt));
if (ctx->freport.mp4_cc_track_cnt) {
printf("MPEG-4 Timed Text tracks count: %d\n", ctx->freport.mp4_cc_track_cnt);
}
memset(&file_report, 0, sizeof (struct file_report_t));
memset(&ctx->freport, 0, sizeof (struct file_report));
#undef Y_N
}

154
src/lib_ccx/sequencing.c Normal file
View File

@@ -0,0 +1,154 @@
#include "lib_ccx.h"
#include "ccx_common_option.h"
// Defined by the maximum number of B-Frames per anchor frame.
//#define MAXBFRAMES 50 - from lib_ccx.h
// They can be (temporally) before or after the anchor. Reserve
// enough space.
//#define SORTBUF (2*MAXBFRAMES+1) - from lib_ccx.h
// B-Frames can be (temporally) before or after the anchor
int cc_data_count[SORTBUF];
// Store fts;
static LLONG cc_fts[SORTBUF];
// Store HD CC packets
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
// Set to true if data is buffered
int has_ccdata_buffered = 0;
// The sequence number of the current anchor frame. All currently read
// B-Frames belong to this I- or P-frame.
static int anchor_seq_number = -1;
void init_hdcc (void)
{
for (int j=0; j<SORTBUF; j++)
{
cc_data_count[j] = 0;
cc_fts[j] = 0;
}
memset(cc_data_pkts, 0, SORTBUF*(31*3+1));
has_ccdata_buffered = 0;
}
// Buffer caption blocks for later sorting/flushing.
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now,struct cc_subtitle *sub)
{
// Uninitialized?
if (anchor_seq_number < 0)
{
anchor_hdcc( sequence_number);
}
int seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
if (seq_index < 0 || seq_index > 2*MAXBFRAMES)
{
// Maybe missing an anchor frame - try to recover
dbg_print(CCX_DMT_VERBOSE, "Too many B-frames, or missing anchor frame. Trying to recover ..\n");
process_hdcc(ctx, sub);
anchor_hdcc( sequence_number);
seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
}
has_ccdata_buffered = 1;
// In GOP mode the fts is set only once for the whole GOP. Recreate
// the right time according to the sequence number.
if (ccx_options.use_gop_as_pts==1)
{
current_fts_now += (LLONG) (sequence_number*1000.0/current_fps);
}
if (cc_count)
{
if (cc_data)
{
// Changed by CFS to concat, i.e. don't assume there's no data already for this seq_index.
// Needed at least for MP4 samples. // TODO: make sure we don't overflow
cc_fts[seq_index] = current_fts_now; // CFS: Maybe do even if there's no data?
if (ctx->stream_mode!=CCX_SM_MP4) // CFS: Very ugly hack, but looks like overwriting is needed for at least some ES
cc_data_count[seq_index] = 0;
memcpy(cc_data_pkts[seq_index]+cc_data_count[seq_index]*3, cc_data, cc_count*3+1);
}
cc_data_count[seq_index] += cc_count;
}
// DEBUG STUFF
/*
printf("\nCC blocks, channel 0:\n");
for ( int i=0; i < cc_count*3; i+=3)
{
printf("%s", debug_608toASC( cc_data+i, 0) );
}
printf("\n");
*/
}
// Set a new anchor frame that new B-frames refer to.
void anchor_hdcc(int seq)
{
// Re-init the index
anchor_seq_number = seq;
}
// Sort/flash caption block buffer
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
{
// Remember the current value
LLONG store_fts_now = fts_now;
struct lib_cc_decode *dec_ctx;
int reset_cb = -1;
dbg_print(CCX_DMT_VERBOSE, "Flush HD caption blocks\n");
dec_ctx = ctx->dec_ctx;
for (int seq=0; seq<SORTBUF; seq++)
{
// We rely on this.
if (ccx_bufferdatatype == CCX_H264)
reset_cb = 1;
// If fts_now is unchanged we rely on cc block counting,
// otherwise reset counters as they get changed by do_cb()
// below. This only happens when current_pts does not get
// updated, like it used do happen for elementary streams.
// Since use_gop_as_pts this is not needed anymore, but left
// here for posterity.
if (reset_cb < 0 && cc_fts[seq] && seq<SORTBUF-1 && cc_fts[seq+1])
{
if (cc_fts[seq] != cc_fts[seq+1])
reset_cb = 1;
else
reset_cb = 0;
}
if (reset_cb == 1)
{
cb_field1 = 0;
cb_field2 = 0;
cb_708 = 0;
}
// Skip sequence numbers without data
if (cc_data_count[seq] == 0)
continue;
if (cc_data_pkts[seq][cc_data_count[seq]*3]!=0xFF)
{
// This is not optional. Something is wrong.
dbg_print(CCX_DMT_VERBOSE, "Missing 0xFF marker at end\n");
// A "continue;" here would ignore this caption, but we
// process it.
}
// Re-create original time
fts_now = cc_fts[seq];
process_cc_data( dec_ctx, cc_data_pkts[seq], cc_data_count[seq], sub);
}
// Restore the value
fts_now = store_fts_now;
// Now that we are done, clean up.
init_hdcc();
}

View File

@@ -5,6 +5,7 @@
#include <assert.h>
#ifdef ENABLE_OCR
#include "ocr.h"
#undef OCR_DEBUG
#endif
#define CCPL (ccfont2_width / CCW * ccfont2_height / CCH)
@@ -333,7 +334,7 @@ void set_spupng_offset(void *ctx,int x,int y)
sp->xOffset = x;
sp->yOffset = y;
}
static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
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;
@@ -430,7 +431,12 @@ static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
return ret;
}
/**
* alpha value 255 means completely opaque
* alpha value 0 means completely transparent
* r g b all 0 means black
* r g b all 255 means white
*/
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
uint8_t depth)
{
@@ -441,167 +447,27 @@ int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
palette[i].blue = (clut[i] & 0xff);
alpha[i] = ((clut[i] >> 24) & 0xff);
}
#if OCR_DEBUG
ccx_common_logging.log_ftn("Colors present in original Image\n");
for (int i = 0; i < depth; 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
return 0;
}
struct transIntensity
{
uint8_t *t;
png_color *palette;
};
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;
}
/*
* @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, 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));
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;
}
int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context)
{
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
int x_pos, y_pos, width, height, i;
int x, y, y_off, x_off, ret;
int x, y, y_off, x_off, ret=0;
uint8_t *pbuf;
char *filename;
struct cc_bitmap* rect;
png_color *palette = NULL;
png_byte *alpha = NULL;
#ifdef ENABLE_OCR
char*str = NULL;
#endif
x_pos = -1;
y_pos = -1;
@@ -685,14 +551,13 @@ int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *conte
ret = -1;
goto end;
}
/* TODO do rectangle, wise one color table should not be used for all rectangle */
/* TODO do rectangle wise, one color table should not be used for all rectangles */
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
#ifdef ENABLE_OCR
str = ocr_bitmap(palette,alpha,pbuf,width,height);
if(str && str[0])
#if ENABLE_OCR
if (rect[0].ocr_text && *(rect[0].ocr_text))
{
write_spucomment(sp,str);
write_spucomment(sp, rect[0].ocr_text);
}
#endif
save_spupng(filename,pbuf,width, height, palette, alpha,rect[0].nb_colors);

View File

@@ -34,6 +34,4 @@ void inc_spupng_fileindex(void *ctx);
void set_spupng_offset(void *ctx,int x,int y);
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
uint8_t depth);
int quantize_map(png_byte *alpha, png_color *palette,
uint8_t *bitmap, int size, int max_color, int nb_color);
#endif

View File

@@ -1,32 +1,32 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2008 Alexander Chemeris
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
@@ -47,7 +47,7 @@
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#if (_MSC_VER < 1300) && defined(__cplusplus)
extern "C++" {
#endif
#endif
# include <wchar.h>
#if (_MSC_VER < 1300) && defined(__cplusplus)
}

View File

@@ -1,173 +1,174 @@
#include "ccextractor.h"
#include "lib_ccx.h"
#include "ccx_common_option.h"
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
void detect_stream_type (void)
void detect_stream_type (struct lib_ccx_ctx *ctx)
{
stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
startbytes_avail = (int) buffered_read_opt (startbytes,STARTBYTESLENGTH);
if( startbytes_avail == -1)
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
ctx->startbytes_avail = (int) buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
if( ctx->startbytes_avail == -1)
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
if (startbytes_avail>=4)
if (ctx->startbytes_avail>=4)
{
// Check for ASF magic bytes
if (startbytes[0]==0x30 &&
startbytes[1]==0x26 &&
startbytes[2]==0xb2 &&
startbytes[3]==0x75)
stream_mode=CCX_SM_ASF;
if (ctx->startbytes[0]==0x30 &&
ctx->startbytes[1]==0x26 &&
ctx->startbytes[2]==0xb2 &&
ctx->startbytes[3]==0x75)
ctx->stream_mode=CCX_SM_ASF;
}
if (stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail >= 4)
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 4)
{
if(startbytes[0]==0xb7 &&
startbytes[1]==0xd8 &&
startbytes[2]==0x00 &&
startbytes[3]==0x20)
stream_mode=CCX_SM_WTV;
if(ctx->startbytes[0]==0xb7 &&
ctx->startbytes[1]==0xd8 &&
ctx->startbytes[2]==0x00 &&
ctx->startbytes[3]==0x20)
ctx->stream_mode = CCX_SM_WTV;
}
#ifdef WTV_DEBUG
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail>=6)
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=6)
{
// Check for hexadecimal dump generated by wtvccdump
// ; CCHD
if (startbytes[0]==';' &&
startbytes[1]==' ' &&
startbytes[2]=='C' &&
startbytes[3]=='C' &&
startbytes[4]=='H' &&
startbytes[5]=='D')
stream_mode= CCX_SM_HEX_DUMP;
if (ctx->startbytes[0]==';' &&
ctx->startbytes[1]==' ' &&
ctx->startbytes[2]=='C' &&
ctx->startbytes[3]=='C' &&
ctx->startbytes[4]=='H' &&
ctx->startbytes[5]=='D')
ctx->stream_mode= CCX_SM_HEX_DUMP;
}
#endif
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail>=11)
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=11)
{
// Check for CCExtractor magic bytes
if (startbytes[0]==0xCC &&
startbytes[1]==0xCC &&
startbytes[2]==0xED &&
startbytes[8]==0 &&
startbytes[9]==0 &&
startbytes[10]==0)
stream_mode=CCX_SM_RCWT;
if (ctx->startbytes[0]==0xCC &&
ctx->startbytes[1]==0xCC &&
ctx->startbytes[2]==0xED &&
ctx->startbytes[8]==0 &&
ctx->startbytes[9]==0 &&
ctx->startbytes[10]==0)
ctx->stream_mode=CCX_SM_RCWT;
}
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
{
if (startbytes_avail > 188*8) // Otherwise, assume no TS
if (ctx->startbytes_avail > 188*8) // Otherwise, assume no TS
{
// First check for TS
for (unsigned i=0; i<188;i++)
{
if (startbytes[i]==0x47 && startbytes[i+188]==0x47 &&
startbytes[i+188*2]==0x47 && startbytes[i+188*3]==0x47 &&
startbytes[i+188*4]==0x47 && startbytes[i+188*5]==0x47 &&
startbytes[i+188*6]==0x47 && startbytes[i+188*7]==0x47
if (ctx->startbytes[i]==0x47 && ctx->startbytes[i+188]==0x47 &&
ctx->startbytes[i+188*2]==0x47 && ctx->startbytes[i+188*3]==0x47 &&
ctx->startbytes[i+188*4]==0x47 && ctx->startbytes[i+188*5]==0x47 &&
ctx->startbytes[i+188*6]==0x47 && ctx->startbytes[i+188*7]==0x47
)
{
// Eight sync bytes, that's good enough
startbytes_pos=i;
stream_mode=CCX_SM_TRANSPORT;
// Eight sync bytes, that's good enough
ctx->startbytes_pos=i;
ctx->stream_mode=CCX_SM_TRANSPORT;
break;
}
}
}
// Now check for PS (Needs PACK header)
for (unsigned i=0;
i < (unsigned) (startbytes_avail<50000?startbytes_avail-3:49997);
i < (unsigned) (ctx->startbytes_avail<50000?ctx->startbytes_avail-3:49997);
i++)
{
if (startbytes[i]==0x00 && startbytes[i+1]==0x00 &&
startbytes[i+2]==0x01 && startbytes[i+3]==0xBA)
if (ctx->startbytes[i]==0x00 && ctx->startbytes[i+1]==0x00 &&
ctx->startbytes[i+2]==0x01 && ctx->startbytes[i+3]==0xBA)
{
// If we find a PACK header it is not an ES
startbytes_pos=i;
stream_mode=CCX_SM_PROGRAM;
ctx->startbytes_pos=i;
ctx->stream_mode=CCX_SM_PROGRAM;
break;
}
}
}
// TiVo is also a PS
if (startbytes[0]=='T' && startbytes[1]=='i' &&
startbytes[2]=='V' && startbytes[3]=='o')
if (ctx->startbytes[0]=='T' && ctx->startbytes[1]=='i' &&
ctx->startbytes[2]=='V' && ctx->startbytes[3]=='o')
{
// The TiVo header is longer, but the PS loop will find the beginning
startbytes_pos=187;
stream_mode=CCX_SM_PROGRAM;
ctx->startbytes_pos=187;
ctx->stream_mode=CCX_SM_PROGRAM;
strangeheader=1; // Avoid message about unrecognized header
}
}
}
else
{
startbytes_pos=0;
stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
ctx->startbytes_pos=0;
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
}
}
if ((stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
&& startbytes_avail>=4) // Still not found
if ((ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
&& ctx->startbytes_avail>=4) // Still not found
{
// Try for MP4 by looking for box signatures - this should happen very
// Try for MP4 by looking for box signatures - this should happen very
// early in the file according to specs
for (int i=0;i<startbytes_avail-3;i++)
for (int i=0;i<ctx->startbytes_avail-3;i++)
{
// Look for the a box of type 'file'
if (
(startbytes[i]=='f' && startbytes[i+1]=='t' &&
startbytes[i+2]=='y' && startbytes[i+3]=='p')
(ctx->startbytes[i]=='f' && ctx->startbytes[i+1]=='t' &&
ctx->startbytes[i+2]=='y' && ctx->startbytes[i+3]=='p')
||
(startbytes[i]=='m' && startbytes[i+1]=='o' &&
startbytes[i+2]=='o' && startbytes[i+3]=='v')
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='o' &&
ctx->startbytes[i+2]=='o' && ctx->startbytes[i+3]=='v')
||
(startbytes[i]=='m' && startbytes[i+1]=='d' &&
startbytes[i+2]=='a' && startbytes[i+3]=='t')
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='d' &&
ctx->startbytes[i+2]=='a' && ctx->startbytes[i+3]=='t')
||
(startbytes[i]=='f' && startbytes[i+1]=='e' &&
startbytes[i+2]=='e' && startbytes[i+3]=='e')
(ctx->startbytes[i]=='f' && ctx->startbytes[i+1]=='e' &&
ctx->startbytes[i+2]=='e' && ctx->startbytes[i+3]=='e')
||
(startbytes[i]=='s' && startbytes[i+1]=='k' &&
startbytes[i+2]=='i' && startbytes[i+3]=='p')
(ctx->startbytes[i]=='s' && ctx->startbytes[i+1]=='k' &&
ctx->startbytes[i+2]=='i' && ctx->startbytes[i+3]=='p')
||
(startbytes[i]=='u' && startbytes[i+1]=='d' &&
startbytes[i+2]=='t' && startbytes[i+3]=='a')
(ctx->startbytes[i]=='u' && ctx->startbytes[i+1]=='d' &&
ctx->startbytes[i+2]=='t' && ctx->startbytes[i+3]=='a')
||
(startbytes[i]=='m' && startbytes[i+1]=='e' &&
startbytes[i+2]=='t' && startbytes[i+3]=='a')
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='e' &&
ctx->startbytes[i+2]=='t' && ctx->startbytes[i+3]=='a')
||
(startbytes[i]=='v' && startbytes[i+1]=='o' &&
startbytes[i+2]=='i' && startbytes[i+3]=='d')
(ctx->startbytes[i]=='v' && ctx->startbytes[i+1]=='o' &&
ctx->startbytes[i+2]=='i' && ctx->startbytes[i+3]=='d')
)
{
stream_mode=CCX_SM_MP4;
ctx->stream_mode=CCX_SM_MP4;
break;
}
}
}
// Don't use STARTBYTESLENGTH. It might be longer than the file length!
return_to_buffer (startbytes, startbytes_avail);
return_to_buffer (ctx->startbytes, ctx->startbytes_avail);
}
int detect_myth( void )
int detect_myth( struct lib_ccx_ctx *ctx )
{
int vbi_blocks=0;
// VBI data? if yes, use myth loop
// STARTBTYTESLENGTH is 1MB, if the file is shorter we will never detect
// it as a mythTV file
if (startbytes_avail==STARTBYTESLENGTH)
if (ctx->startbytes_avail==STARTBYTESLENGTH)
{
unsigned char uc[3];
memcpy (uc,startbytes,3);
for (int i=3;i<startbytes_avail;i++)
memcpy (uc,ctx->startbytes,3);
for (int i=3;i<ctx->startbytes_avail;i++)
{
if (((uc[0]=='t') && (uc[1]=='v') && (uc[2] == '0')) ||
((uc[0]=='T') && (uc[1]=='V') && (uc[2] == '0')))
vbi_blocks++;
uc[0]=uc[1];
uc[1]=uc[2];
uc[2]=startbytes[i];
}
uc[2]=ctx->startbytes[i];
}
}
if (vbi_blocks>10) // Too much coincidence
return 1;
@@ -185,24 +186,24 @@ int read_pts_pes(unsigned char*header, int len)
//function used only to set start time
if(pts_set)
return -1;
return -1;
//it might not be pes packet
if (!(header[0] == 0 && header[1] == 0 && header[2] == 1))
return -1;
if (!(header[0] == 0 && header[1] == 0 && header[2] == 1))
return -1;
/* peslen = header[4] << 8 | header[5]; */
if (header[7] & 0x80)
{
{
bits_9 = ((LLONG) header[9] & 0x0E) << 29; // PTS 32..30 - Must be LLONG to prevent overflow
bits_10 = header[10] << 22; // PTS 29..22
bits_11 = (header[11] & 0xFE) << 14; // PTS 21..15
bits_12 = header[12] << 7; // PTS 14-7
bits_13 = header[13] >> 1; // PTS 6-0
}
}
else
return -1;
return -1;
current_pts = bits_9 | bits_10 | bits_11 | bits_12 | bits_13;
pts_set = 1;
@@ -216,7 +217,7 @@ int read_pts_pes(unsigned char*header, int len)
* 0 .. Read from file into nextheader
* >0 .. Use data in nextheader with the length of sbuflen
*/
int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbuflen)
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen)
{
// Read the next video PES
// ((nextheader[3]&0xf0)==0xe0)
@@ -227,8 +228,8 @@ int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbu
if ( !sbuflen )
{
// Extension present, get it
buffered_read (nextheader+6,3);
past=past+result;
buffered_read (ctx, nextheader+6,3);
ctx->past=ctx->past+result;
if (result!=3) {
// Consider this the end of the show.
return -1;
@@ -248,8 +249,8 @@ int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbu
if ( !sbuflen )
{
if (nextheader[8] > 0) {
buffered_read (nextheader+9,nextheader[8]);
past=past+result;
buffered_read (ctx, nextheader+9,nextheader[8]);
ctx->past=ctx->past+result;
if (result!=nextheader[8]) {
return -1;
}
@@ -329,13 +330,13 @@ int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbu
if ( !falsepes && nextheader[7]&0x80 ) {
// Read PTS from byte 9,10,11,12,13
LLONG bits_9 = ((LLONG) nextheader[9] & 0x0E)<<29; // PTS 32..30 - Must be LLONG to prevent overflow
LLONG bits_9 = ((LLONG) nextheader[9] & 0x0E)<<29; // PTS 32..30 - Must be LLONG to prevent overflow
unsigned bits_10 = nextheader[10] << 22; // PTS 29..22
unsigned bits_11 = (nextheader[11] & 0xFE) << 14; // PTS 21..15
unsigned bits_12 = nextheader[12] << 7; // PTS 14-7
unsigned bits_13 = nextheader[13] >> 1; // PTS 6-0
if (pts_set) // Otherwise can't check for rollovers yet
{
if (!bits_9 && ((current_pts_33>>30)&7)==7) // PTS about to rollover

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