diff --git a/docs/COMPILATION.MD b/docs/COMPILATION.MD index 172121022..67441040b 100644 --- a/docs/COMPILATION.MD +++ b/docs/COMPILATION.MD @@ -113,7 +113,6 @@ sudo make install `cmake` also accepts the options: `-DWITH_OCR=ON` to enable OCR - `-DWITHOUT_RUST=ON` to disable rust. `-DWITH_HARDSUBX=ON` to enable burned-in subtitles ([OPTIONAL] For hardsubx, you also need to set these environment variables correctly according to your machine) @@ -176,7 +175,6 @@ make `cmake` also accepts the options: `-DWITH_OCR=ON` to enable OCR - `-DWITHOUT_RUST=ON` to disable rust. `-DWITH_HARDSUBX=ON` to enable burned-in subtitles #### Standard compilation through Autoconf scripts: diff --git a/docs/using_cmake_build.txt b/docs/using_cmake_build.txt index af842fbb8..1e9ad3fa4 100644 --- a/docs/using_cmake_build.txt +++ b/docs/using_cmake_build.txt @@ -32,8 +32,5 @@ cmake -DWITH_OCR=ON ../src/ If you want to build CCExtractor with HARDSUBX support cmake -DWITH_HARDSUBX=ON ../src/ -If you want to build CCExtractor with rust disabled you need to pass -cmake -DWITHOUT_RUST=ON ../src/ - Hint for looking all the things you want to set from outside cmake -LAH ../src/ diff --git a/linux/Makefile.am b/linux/Makefile.am index 0b45a5d99..00bd7bee3 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -327,12 +327,7 @@ ccextractor_LDADD += $(TESS_LIB) ccextractor_LDADD += $(LEPT_LIB) endif -if WITH_RUST ccextractor_LDADD += ./rust/@RUST_TARGET_SUBDIR@/libccx_rust.a -else -ccextractor_CFLAGS += -DDISABLE_RUST -ccextractor_CPPFLAGS += -DDISABLE_RUST -endif if DEBUG_RELEASE CARGO_RELEASE_ARGS= diff --git a/linux/build b/linux/build index 78fa63c8f..022572952 100755 --- a/linux/build +++ b/linux/build @@ -11,10 +11,6 @@ while [[ $# -gt 0 ]]; do RUST_LIB="rust/debug/libccx_rust.a" shift ;; - -without-rust) - WITHOUT_RUST=true - shift - ;; -hardsubx) HARDSUBX=true RUST_FEATURES="--features hardsubx_ocr" @@ -90,34 +86,29 @@ echo "Running pre-build script..." ./pre-build.sh echo "Trying to compile..." -if [ "$WITHOUT_RUST" = true ]; then - echo "Building without rust files..." - BLD_FLAGS="$BLD_FLAGS -DDISABLE_RUST" -else - BLD_LINKER="$BLD_LINKER ./libccx_rust.a" - echo "Checking for cargo..." - if ! [ -x "$(command -v cargo)" ]; then - echo 'Error: cargo is not installed.' >&2 - exit 1 - fi - - rustc_version="$(rustc --version)" - semver=( ${rustc_version//./ } ) - version="${semver[1]}.${semver[2]}.${semver[3]}" - MSRV="1.54.0" - if [ "$(printf '%s\n' "$MSRV" "$version" | sort -V | head -n1)" = "$MSRV" ]; then - echo "rustc >= MSRV(${MSRV})" - else - echo "Minimum supported rust version(MSRV) is ${MSRV}, please upgrade rust" - exit 1 - fi - - echo "Building rust files..." - (cd ../src/rust && CARGO_TARGET_DIR=../../linux/rust cargo build $RUST_PROFILE $RUST_FEATURES) || { echo "Failed. " ; exit 1; } +BLD_LINKER="$BLD_LINKER ./libccx_rust.a" +echo "Checking for cargo..." +if ! [ -x "$(command -v cargo)" ]; then + echo 'Error: cargo is not installed.' >&2 + exit 1 +fi - cp $RUST_LIB ./libccx_rust.a +rustc_version="$(rustc --version)" +semver=( ${rustc_version//./ } ) +version="${semver[1]}.${semver[2]}.${semver[3]}" +MSRV="1.54.0" +if [ "$(printf '%s\n' "$MSRV" "$version" | sort -V | head -n1)" = "$MSRV" ]; then + echo "rustc >= MSRV(${MSRV})" +else + echo "Minimum supported rust version(MSRV) is ${MSRV}, please upgrade rust" + exit 1 fi +echo "Building rust files..." +(cd ../src/rust && CARGO_TARGET_DIR=../../linux/rust cargo build $RUST_PROFILE $RUST_FEATURES) || { echo "Failed. " ; exit 1; } + +cp $RUST_LIB ./libccx_rust.a + echo "Building ccextractor" out=$((LC_ALL=C gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER)2>&1) res=$? diff --git a/mac/Makefile.am b/mac/Makefile.am index 478d9c706..3b98d4490 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -300,12 +300,8 @@ ccextractor_LDADD += $(TESS_LIB) ccextractor_LDADD += $(LEPT_LIB) endif -if WITH_RUST ccextractor_LDADD += ./rust/@RUST_TARGET_SUBDIR@/libccx_rust.a -else -ccextractor_CFLAGS += -DDISABLE_RUST -ccextractor_CPPFLAGS += -DDISABLE_RUST -endif + if DEBUG_RELEASE CARGO_RELEASE_ARGS= diff --git a/mac/build.command b/mac/build.command index 1e0b83281..77013a5e6 100755 --- a/mac/build.command +++ b/mac/build.command @@ -1,58 +1,183 @@ #!/bin/bash cd `dirname $0` -BLD_FLAGS="-std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -DFT2_BUILD_LIBRARY -DGPAC_DISABLE_VTT -DGPAC_DISABLE_OD_DUMP -DGPAC_DISABLE_REMOTERY -DNO_GZIP -DDISABLE_RUST" -[[ $1 = "OCR" ]] && BLD_FLAGS="$BLD_FLAGS -DENABLE_OCR" + +RUST_LIB="rust/release/libccx_rust.a" +RUST_PROFILE="--release" +RUST_FEATURES="" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + OCR) + ENABLE_OCR=true + shift + ;; + -debug) + DEBUG=true + RUST_PROFILE="" + RUST_LIB="rust/debug/libccx_rust.a" + shift + ;; + -hardsubx) + HARDSUBX=true + RUST_FEATURES="--features hardsubx_ocr" + shift + ;; + -*) + echo "Unknown option $1" + exit 1 + ;; + esac +done + +BLD_FLAGS="-std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -DFT2_BUILD_LIBRARY -DGPAC_DISABLE_VTT -DGPAC_DISABLE_OD_DUMP -DGPAC_DISABLE_REMOTERY -DNO_GZIP" + +# Add debug flags if needed +if [[ "$DEBUG" == "true" ]]; then + BLD_FLAGS="$BLD_FLAGS -g -fsanitize=address" +fi + +# Add OCR support if requested +if [[ "$ENABLE_OCR" == "true" ]]; then + BLD_FLAGS="$BLD_FLAGS -DENABLE_OCR" +fi + +# Add hardsubx support if requested +if [[ "$HARDSUBX" == "true" ]]; then + BLD_FLAGS="$BLD_FLAGS -DENABLE_HARDSUBX" +fi + BLD_INCLUDE="-I../src/ -I../src/lib_ccx -I../src/lib_hash -I../src/thirdparty/libpng -I../src/thirdparty -I../src/thirdparty/zlib -I../src/thirdparty/freetype/include `pkg-config --cflags --silence-errors gpac`" -[[ $1 = "OCR" ]] && BLD_INCLUDE="$BLD_INCLUDE `pkg-config --cflags --silence-errors tesseract`" + +if [[ "$ENABLE_OCR" == "true" ]]; then + BLD_INCLUDE="$BLD_INCLUDE `pkg-config --cflags --silence-errors tesseract`" +fi + SRC_CCX="$(find ../src/lib_ccx -name '*.c')" SRC_LIB_HASH="$(find ../src/thirdparty/lib_hash -name '*.c')" SRC_LIBPNG="$(find ../src/thirdparty/libpng -name '*.c')" SRC_UTF8="../src/thirdparty/utf8proc/utf8proc.c" SRC_ZLIB="$(find ../src/thirdparty/zlib -name '*.c')" SRC_FREETYPE="../src/thirdparty/freetype/autofit/autofit.c \ - ../src/thirdparty/freetype/base/ftbase.c \ - ../src/thirdparty/freetype/base/ftbbox.c \ - ../src/thirdparty/freetype/base/ftbdf.c \ - ../src/thirdparty/freetype/base/ftbitmap.c \ - ../src/thirdparty/freetype/base/ftcid.c \ - ../src/thirdparty/freetype/base/ftfntfmt.c \ - ../src/thirdparty/freetype/base/ftfstype.c \ - ../src/thirdparty/freetype/base/ftgasp.c \ - ../src/thirdparty/freetype/base/ftglyph.c \ - ../src/thirdparty/freetype/base/ftgxval.c \ - ../src/thirdparty/freetype/base/ftinit.c \ - ../src/thirdparty/freetype/base/ftlcdfil.c \ - ../src/thirdparty/freetype/base/ftmm.c \ - ../src/thirdparty/freetype/base/ftotval.c \ - ../src/thirdparty/freetype/base/ftpatent.c \ - ../src/thirdparty/freetype/base/ftpfr.c \ - ../src/thirdparty/freetype/base/ftstroke.c \ - ../src/thirdparty/freetype/base/ftsynth.c \ - ../src/thirdparty/freetype/base/ftsystem.c \ - ../src/thirdparty/freetype/base/fttype1.c \ - ../src/thirdparty/freetype/base/ftwinfnt.c \ - ../src/thirdparty/freetype/bdf/bdf.c \ - ../src/thirdparty/freetype/bzip2/ftbzip2.c \ - ../src/thirdparty/freetype/cache/ftcache.c \ - ../src/thirdparty/freetype/cff/cff.c \ - ../src/thirdparty/freetype/cid/type1cid.c \ - ../src/thirdparty/freetype/gzip/ftgzip.c \ - ../src/thirdparty/freetype/lzw/ftlzw.c \ - ../src/thirdparty/freetype/pcf/pcf.c \ - ../src/thirdparty/freetype/pfr/pfr.c \ - ../src/thirdparty/freetype/psaux/psaux.c \ - ../src/thirdparty/freetype/pshinter/pshinter.c \ - ../src/thirdparty/freetype/psnames/psnames.c \ - ../src/thirdparty/freetype/raster/raster.c \ - ../src/thirdparty/freetype/sfnt/sfnt.c \ - ../src/thirdparty/freetype/smooth/smooth.c \ - ../src/thirdparty/freetype/truetype/truetype.c \ - ../src/thirdparty/freetype/type1/type1.c \ - ../src/thirdparty/freetype/type42/type42.c \ - ../src/thirdparty/freetype/winfonts/winfnt.c" -BLD_SOURCES="../src/ccextractor.c $SRC_API $SRC_CCX $SRC_LIB_HASH $SRC_LIBPNG $SRC_UTF8 $SRC_ZLIB $SRC_ZVBI $SRC_FREETYPE" -BLD_LINKER="-lm -liconv -lpthread -ldl `pkg-config --libs --silence-errors tesseract` `pkg-config --libs --silence-errors gpac`" -[[ $1 = "OCR" ]] && BLD_LINKER="$BLD_LINKER `pkg-config --libs --silence-errors tesseract` `pkg-config --libs --silence-errors lept`" + ../src/thirdparty/freetype/base/ftbase.c \ + ../src/thirdparty/freetype/base/ftbbox.c \ + ../src/thirdparty/freetype/base/ftbdf.c \ + ../src/thirdparty/freetype/base/ftbitmap.c \ + ../src/thirdparty/freetype/base/ftcid.c \ + ../src/thirdparty/freetype/base/ftfntfmt.c \ + ../src/thirdparty/freetype/base/ftfstype.c \ + ../src/thirdparty/freetype/base/ftgasp.c \ + ../src/thirdparty/freetype/base/ftglyph.c \ + ../src/thirdparty/freetype/base/ftgxval.c \ + ../src/thirdparty/freetype/base/ftinit.c \ + ../src/thirdparty/freetype/base/ftlcdfil.c \ + ../src/thirdparty/freetype/base/ftmm.c \ + ../src/thirdparty/freetype/base/ftotval.c \ + ../src/thirdparty/freetype/base/ftpatent.c \ + ../src/thirdparty/freetype/base/ftpfr.c \ + ../src/thirdparty/freetype/base/ftstroke.c \ + ../src/thirdparty/freetype/base/ftsynth.c \ + ../src/thirdparty/freetype/base/ftsystem.c \ + ../src/thirdparty/freetype/base/fttype1.c \ + ../src/thirdparty/freetype/base/ftwinfnt.c \ + ../src/thirdparty/freetype/bdf/bdf.c \ + ../src/thirdparty/freetype/bzip2/ftbzip2.c \ + ../src/thirdparty/freetype/cache/ftcache.c \ + ../src/thirdparty/freetype/cff/cff.c \ + ../src/thirdparty/freetype/cid/type1cid.c \ + ../src/thirdparty/freetype/gzip/ftgzip.c \ + ../src/thirdparty/freetype/lzw/ftlzw.c \ + ../src/thirdparty/freetype/pcf/pcf.c \ + ../src/thirdparty/freetype/pfr/pfr.c \ + ../src/thirdparty/freetype/psaux/psaux.c \ + ../src/thirdparty/freetype/pshinter/pshinter.c \ + ../src/thirdparty/freetype/psnames/psnames.c \ + ../src/thirdparty/freetype/raster/raster.c \ + ../src/thirdparty/freetype/sfnt/sfnt.c \ + ../src/thirdparty/freetype/smooth/smooth.c \ + ../src/thirdparty/freetype/truetype/truetype.c \ + ../src/thirdparty/freetype/type1/type1.c \ + ../src/thirdparty/freetype/type42/type42.c \ + ../src/thirdparty/freetype/winfonts/winfnt.c" + +BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_LIB_HASH $SRC_LIBPNG $SRC_UTF8 $SRC_ZLIB $SRC_FREETYPE" + +BLD_LINKER="-lm -liconv -lpthread -ldl `pkg-config --libs --silence-errors gpac`" + +if [[ "$ENABLE_OCR" == "true" ]]; then + BLD_LINKER="$BLD_LINKER `pkg-config --libs --silence-errors tesseract` `pkg-config --libs --silence-errors lept`" +fi + +if [[ "$HARDSUBX" == "true" ]]; then + BLD_LINKER="$BLD_LINKER -lswscale -lavutil -pthread -lavformat -lavcodec -lavfilter" +fi +echo "Running pre-build script..." ./pre-build.sh -gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER +echo "Trying to compile..." + +# Check for cargo +echo "Checking for cargo..." +if ! [ -x "$(command -v cargo)" ]; then + echo 'Error: cargo is not installed.' >&2 + exit 1 +fi + +# Check rust version +rustc_version="$(rustc --version)" +semver=( ${rustc_version//./ } ) +version="${semver[1]}.${semver[2]}.${semver[3]}" +MSRV="1.54.0" +if [ "$(printf '%s\n' "$MSRV" "$version" | sort -V | head -n1)" = "$MSRV" ]; then + echo "rustc >= MSRV(${MSRV})" +else + echo "Minimum supported rust version(MSRV) is ${MSRV}, please upgrade rust" + exit 1 +fi + +echo "Building rust files..." +(cd ../src/rust && CARGO_TARGET_DIR=../../mac/rust cargo build $RUST_PROFILE $RUST_FEATURES) || { echo "Failed building Rust components." ; exit 1; } + +# Copy the Rust library +cp $RUST_LIB ./libccx_rust.a + +# Add Rust library to linker flags +BLD_LINKER="$BLD_LINKER ./libccx_rust.a" + +echo "Building ccextractor" +out=$((LC_ALL=C gcc $BLD_FLAGS $BLD_INCLUDE -o ccextractor $BLD_SOURCES $BLD_LINKER) 2>&1) +res=$? + +# Handle common error cases +if [[ $out == *"gcc: command not found"* ]]; then + echo "Error: please install gcc or Xcode command line tools" + exit 1 +fi + +if [[ $out == *"curl.h: No such file or directory"* ]]; then + echo "Error: please install curl development library" + exit 2 +fi + +if [[ $out == *"capi.h: No such file or directory"* ]]; then + echo "Error: please install tesseract development library" + exit 3 +fi + +if [[ $out == *"allheaders.h: No such file or directory"* ]]; then + echo "Error: please install leptonica development library" + exit 4 +fi + +if [[ $res -ne 0 ]]; then # Unknown error + echo "Compiled with errors" + >&2 echo "$out" + exit 5 +fi + +if [[ "$out" != "" ]]; then + echo "$out" + echo "Compilation successful, compiler message shown in previous lines" +else + echo "Compilation successful, no compiler messages." +fi \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5bd1526fd..5611f0656 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,7 +6,6 @@ include (CTest) option (WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF) option (WITH_OCR "Build with OCR (Optical Character Recognition) feature" OFF) option (WITH_HARDSUBX "Build with support for burned-in subtitles" OFF) -option (WITHOUT_RUST "Build without Rust library" OFF) # Version number set (CCEXTRACTOR_VERSION_MAJOR 0) @@ -237,12 +236,10 @@ add_executable (ccextractor ${SOURCEFILE} ${FREETYPE_SOURCE} ${UTF8PROC_SOURCE}) # Build with Rust library ######################################################## -if (PKG_CONFIG_FOUND AND NOT WITHOUT_RUST) +if (PKG_CONFIG_FOUND) add_subdirectory (rust) set (EXTRA_LIBS ${EXTRA_LIBS} ccx_rust) -else () - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDISABLE_RUST") -endif (PKG_CONFIG_FOUND AND NOT WITHOUT_RUST) +endif (PKG_CONFIG_FOUND) target_link_libraries (ccextractor ${EXTRA_LIBS}) diff --git a/src/ccextractor.c b/src/ccextractor.c index f2ef89a1d..2fa926024 100644 --- a/src/ccextractor.c +++ b/src/ccextractor.c @@ -418,15 +418,9 @@ int main(int argc, char *argv[]) // See docs/ccextractor.cnf.sample for more info. parse_configuration(&ccx_options); -#ifndef DISABLE_RUST ccxr_init_basic_logger(); -#endif -#ifndef DISABLE_RUST int compile_ret = ccxr_parse_parameters(argc, argv); -#else - int compile_ret = parse_parameters(&ccx_options, argc, argv); -#endif if (compile_ret == EXIT_NO_INPUT_FILES) { diff --git a/src/lib_ccx/CMakeLists.txt b/src/lib_ccx/CMakeLists.txt index 11b25b52f..befb4f18b 100644 --- a/src/lib_ccx/CMakeLists.txt +++ b/src/lib_ccx/CMakeLists.txt @@ -87,10 +87,6 @@ if (WITH_HARDSUBX) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_HARDSUBX") endif (WITH_HARDSUBX) -if (WITHOUT_RUST) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDISABLE_RUST") -endif (WITHOUT_RUST) - file (GLOB HeaderFiles *.h) file (WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n" "includedir=\${prefix}/include\n" diff --git a/src/lib_ccx/cc_bitstream.c b/src/lib_ccx/cc_bitstream.c index ac9b0bee9..bb183dd2b 100644 --- a/src/lib_ccx/cc_bitstream.c +++ b/src/lib_ccx/cc_bitstream.c @@ -3,7 +3,6 @@ // Hold functions to read streams on a bit or byte oriented basis // plus some data related helper functions. -#ifndef DISABLE_RUST extern uint64_t ccxr_next_bits(struct bitstream *bs, uint32_t bnum); extern uint64_t ccxr_read_bits(struct bitstream *bs, uint32_t bnum); extern int ccxr_skip_bits(struct bitstream *bs, uint32_t bnum); @@ -16,7 +15,6 @@ extern int64_t ccxr_read_exp_golomb(struct bitstream *bs); extern uint8_t ccxr_reverse8(uint8_t data); extern uint64_t ccxr_bitstream_get_num(struct bitstream *bs, unsigned bytes, int advance); extern int64_t ccxr_read_int(struct bitstream *bs, unsigned bnum); -#endif // Guidelines for all bitsream functions: // * No function shall advance the pointer past the end marker @@ -50,96 +48,14 @@ int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char * // there are not enough bits left in the bitstream. uint64_t next_bits(struct bitstream *bstr, unsigned bnum) { -#ifndef DISABLE_RUST return ccxr_next_bits(bstr, bnum); -#else - uint64_t res = 0; - - if (bnum > 64) - fatal(CCX_COMMON_EXIT_BUG_BUG, "In next_bits: Argument is greater than the maximum bit number i.e. 64: %u!", bnum); - - // Sanity check - if (bstr->end - bstr->pos < 0) - fatal(CCX_COMMON_EXIT_BUG_BUG, "In next_bits: Bitstream can not have negative length!"); - - // Keep a negative bitstream.bitsleft, but correct it. - if (bstr->bitsleft <= 0) - { - bstr->bitsleft -= bnum; - return 0; - } - - // Calculate the remaining number of bits in bitstream after reading. - bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1) * 8 + bstr->bpos - bnum; - if (bstr->bitsleft < 0) - return 0; - - // Special case for reading zero bits. Return zero - if (bnum == 0) - return 0; - - int vbit = bstr->bpos; - unsigned char *vpos = bstr->pos; - - if (vbit < 1 || vbit > 8) - { - fatal(CCX_COMMON_EXIT_BUG_BUG, "In next_bits: Illegal bit position value %d!", vbit); - } - - while (1) - { - if (vpos >= bstr->end) - { - // We should not get here ... - fatal(CCX_COMMON_EXIT_BUG_BUG, "In next_bits: Trying to read after end of data ..."); - } - - res |= (*vpos & (0x01 << (vbit - 1)) ? 1 : 0); - vbit--; - bnum--; - - if (vbit == 0) - { - vpos++; - vbit = 8; - } - - if (bnum) - { - res <<= 1; - } - else - break; - } - - // Remember the bitstream position - bstr->_i_bpos = vbit; - bstr->_i_pos = vpos; - - return res; -#endif } // Read bnum bits from bitstream bstr with the most significant // bit read first. A 64 bit unsigned integer is returned. uint64_t read_bits(struct bitstream *bstr, unsigned bnum) { -#ifndef DISABLE_RUST return ccxr_read_bits(bstr, bnum); -#else - uint64_t res = next_bits(bstr, bnum); - - // Special case for reading zero bits. Also abort when not enough - // bits are left. Return zero - if (bnum == 0 || bstr->bitsleft < 0) - return 0; - - // Advance the bitstream - bstr->bpos = bstr->_i_bpos; - bstr->pos = bstr->_i_pos; - - return res; -#endif } // This function will advance the bitstream by bnum bits, if possible. @@ -147,39 +63,7 @@ uint64_t read_bits(struct bitstream *bstr, unsigned bnum) // Return TRUE when successful, otherwise FALSE int skip_bits(struct bitstream *bstr, unsigned bnum) { -#ifndef DISABLE_RUST return ccxr_skip_bits(bstr, bnum); -#else - // Sanity check - if (bstr->end - bstr->pos < 0) - fatal(CCX_COMMON_EXIT_BUG_BUG, "In skip_bits: bitstream length cannot be negative!"); - - // Keep a negative bstr->bitsleft, but correct it. - if (bstr->bitsleft < 0) - { - bstr->bitsleft -= bnum; - return 0; - } - - // Calculate the remaining number of bits in bitstream after reading. - bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1) * 8 + bstr->bpos - bnum; - if (bstr->bitsleft < 0) - return 0; - - // Special case for reading zero bits. Return one == success - if (bnum == 0) - return 1; - - bstr->bpos -= bnum % 8; - bstr->pos += bnum / 8; - - if (bstr->bpos < 1) - { - bstr->bpos += 8; - bstr->pos += 1; - } - return 1; -#endif } // Return TRUE if the current position in the bitstream is on a byte @@ -187,62 +71,13 @@ int skip_bits(struct bitstream *bstr, unsigned bnum) // a byte, otherwise return FALSE int is_byte_aligned(struct bitstream *bstr) { -#ifndef DISABLE_RUST return ccxr_is_byte_aligned(bstr); -#else - // Sanity check - if (bstr->end - bstr->pos < 0) - fatal(CCX_COMMON_EXIT_BUG_BUG, "In is_byte_aligned: bitstream length can not be negative!"); - - int vbit = bstr->bpos; - - if (vbit == 0 || vbit > 8) - { - fatal(CCX_COMMON_EXIT_BUG_BUG, "In is_byte_aligned: Illegal bit position value %d!\n", vbit); - } - - if (vbit == 8) - return 1; - else - return 0; -#endif } // Move bitstream to next byte border. Adjust bitsleft. void make_byte_aligned(struct bitstream *bstr) { -#ifndef DISABLE_RUST ccxr_make_byte_aligned(bstr); -#else - // Sanity check - if (bstr->end - bstr->pos < 0) - fatal(CCX_COMMON_EXIT_BUG_BUG, "In make_byte_aligned: bitstream length can not be negative!"); - - int vbit = bstr->bpos; - - if (vbit == 0 || vbit > 8) - { - fatal(CCX_COMMON_EXIT_BUG_BUG, "In make_byte_aligned: Illegal bit position value %d!\n", vbit); - } - - // Keep a negative bstr->bitsleft, but correct it. - if (bstr->bitsleft < 0) - { - // Pay attention to the bit alignment - bstr->bitsleft = (bstr->bitsleft - 7) / 8 * 8; - return; - } - - if (bstr->bpos != 8) - { - bstr->bpos = 8; - bstr->pos += 1; - } - // Reset, in case a next_???() function was used before - bstr->bitsleft = 0LL + 8 * (bstr->end - bstr->pos - 1) + bstr->bpos; - - return; -#endif } // Return pointer to first of bynum bytes from the bitstream if the @@ -252,31 +87,7 @@ void make_byte_aligned(struct bitstream *bstr) // This function does not advance the bitstream pointer. unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum) { -#ifndef DISABLE_RUST return (unsigned char *)ccxr_next_bytes(bstr, bynum); -#else - // Sanity check - if (bstr->end - bstr->pos < 0) - fatal(CCX_COMMON_EXIT_BUG_BUG, "In next_bytes: bitstream length can not be negative!"); - - // Keep a negative bstr->bitsleft, but correct it. - if (bstr->bitsleft < 0) - { - bstr->bitsleft -= bynum * 8; - return NULL; - } - - bstr->bitsleft = 0LL + (bstr->end - bstr->pos - 1) * 8 + bstr->bpos - bynum * 8; - - if (!is_byte_aligned(bstr) || bstr->bitsleft < 0 || bynum < 1) - return NULL; - - // Remember the bitstream position - bstr->_i_bpos = 8; - bstr->_i_pos = bstr->pos + bynum; - - return bstr->pos; -#endif } // Return pointer to first of bynum bytes from the bitstream if the @@ -286,19 +97,7 @@ unsigned char *next_bytes(struct bitstream *bstr, unsigned bynum) // This function does advance the bitstream pointer. unsigned char *read_bytes(struct bitstream *bstr, unsigned bynum) { -#ifndef DISABLE_RUST return (unsigned char *)ccxr_read_bytes(bstr, bynum); -#else - unsigned char *res = next_bytes(bstr, bynum); - - // Advance the bitstream when a read was possible - if (res) - { - bstr->bpos = bstr->_i_bpos; - bstr->pos = bstr->_i_pos; - } - return res; -#endif } // Return an integer number with "bytes" precision from the current @@ -309,77 +108,19 @@ unsigned char *read_bytes(struct bitstream *bstr, unsigned bynum) // little-endian and big-endian CPUs. uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance) { -#ifndef DISABLE_RUST return ccxr_bitstream_get_num(bstr, bytes, advance); -#else - void *bpos; - uint64_t rval = 0; - - if (advance) - bpos = read_bytes(bstr, bytes); - else - bpos = next_bytes(bstr, bytes); - - if (!bpos) - return 0; - - switch (bytes) - { - case 1: - case 2: - case 4: - case 8: - break; - default: - fatal(CCX_COMMON_EXIT_BUG_BUG, "In bitstream_get_num: Illegal precision value [%u]!", - bytes); - break; - } - for (unsigned i = 0; i < bytes; i++) - { - unsigned char *ucpos = ((unsigned char *)bpos) + bytes - i - 1; // Read backwards - unsigned char uc = *ucpos; - rval = (rval << 8) + uc; - } - return rval; -#endif } // Read unsigned Exp-Golomb code from bitstream uint64_t read_exp_golomb_unsigned(struct bitstream *bstr) { -#ifndef DISABLE_RUST return ccxr_read_exp_golomb_unsigned(bstr); -#else - uint64_t res = 0; - int zeros = 0; - - while (!read_bits(bstr, 1) && bstr->bitsleft >= 0) - zeros++; - - res = (0x01 << zeros) - 1 + read_bits(bstr, zeros); - - return res; -#endif } // Read signed Exp-Golomb code from bitstream int64_t read_exp_golomb(struct bitstream *bstr) { -#ifndef DISABLE_RUST return ccxr_read_exp_golomb(bstr); -#else - int64_t res = 0; - - res = read_exp_golomb_unsigned(bstr); - - // The following function might truncate when res+1 overflows - // res = (res+1)/2 * (res % 2 ? 1 : -1); - // Use this: - res = (res / 2 + (res % 2 ? 1 : 0)) * (res % 2 ? 1 : -1); - - return res; -#endif } // Read unsigned integer with bnum bits length. Basically an @@ -392,33 +133,11 @@ uint64_t read_int_unsigned(struct bitstream *bstr, unsigned bnum) // Read signed integer with bnum bits length. int64_t read_int(struct bitstream *bstr, unsigned bnum) { -#ifndef DISABLE_RUST return ccxr_read_int(bstr, bnum); -#else - uint64_t res = read_bits(bstr, bnum); - - // Special case for reading zero bits. Return zero - if (bnum == 0) - return 0; - - return (0xFFFFFFFFFFFFFFFFULL << bnum) | res; -#endif } // Return the value with the bit order reversed. uint8_t reverse8(uint8_t data) { -#ifndef DISABLE_RUST return ccxr_reverse8(data); -#else - uint8_t res = 0; - - for (int k = 0; k < 8; k++) - { - res <<= 1; - res |= (data & (0x01 << k) ? 1 : 0); - } - - return res; -#endif } diff --git a/src/lib_ccx/ccx_common_common.c b/src/lib_ccx/ccx_common_common.c index f150da7d2..0095ede51 100644 --- a/src/lib_ccx/ccx_common_common.c +++ b/src/lib_ccx/ccx_common_common.c @@ -26,17 +26,7 @@ int fdprintf(int fd, const char *fmt, ...) void millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes, unsigned *seconds, unsigned *ms) { -#ifndef DISABLE_RUST return ccxr_millis_to_time(milli, hours, minutes, seconds, ms); -#endif /* ifndef DISABLE_RUST */ - // LLONG milli = (LLONG) ((ccblock*1000)/29.97); - *ms = (unsigned)(milli % 1000); // milliseconds - milli = (milli - *ms) / 1000; // Remainder, in seconds - *seconds = (int)milli % 60; - milli = (milli - *seconds) / 60; // Remainder, in minutes - *minutes = (int)(milli % 60); - milli = (milli - *minutes) / 60; // Remainder, in hours - *hours = (int)milli; } /* Frees the given pointer */ diff --git a/src/lib_ccx/ccx_common_common.h b/src/lib_ccx/ccx_common_common.h index d9f6c3218..76e02d582 100644 --- a/src/lib_ccx/ccx_common_common.h +++ b/src/lib_ccx/ccx_common_common.h @@ -44,9 +44,7 @@ int cc608_parity(unsigned int byte); int fdprintf(int fd, const char *fmt, ...); void millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms); -#ifndef DISABLE_RUST extern void ccxr_millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms); -#endif // !DISABLE_RUST void freep(void *arg); void dbg_print(LLONG mask, const char *fmt, ...); diff --git a/src/lib_ccx/ccx_common_timing.c b/src/lib_ccx/ccx_common_timing.c index b02151bdf..3c97e8ea1 100644 --- a/src/lib_ccx/ccx_common_timing.c +++ b/src/lib_ccx/ccx_common_timing.c @@ -30,7 +30,6 @@ int gop_rollover = 0; struct ccx_common_timing_settings_t ccx_common_timing_settings; -#ifndef DISABLE_RUST void ccxr_add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts); void ccxr_set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts); int ccxr_set_fts(struct ccx_common_timing_ctx *ctx); @@ -40,7 +39,6 @@ char *ccxr_print_mstime_static(LLONG mstime, char *buf); void ccxr_print_debug_timing(struct ccx_common_timing_ctx *ctx); void ccxr_calculate_ms_gop_time(struct gop_time_code *g); int ccxr_gop_accepted(struct gop_time_code *g); -#endif void ccx_common_timing_init(LLONG *file_position, int no_sync) { @@ -85,244 +83,27 @@ struct ccx_common_timing_ctx *init_timing_ctx(struct ccx_common_timing_settings_ void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts) { -#ifndef DISABLE_RUST return ccxr_add_current_pts(ctx, pts); -#endif - - set_current_pts(ctx, ctx->current_pts + pts); } void set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts) { -#ifndef DISABLE_RUST return ccxr_set_current_pts(ctx, pts); -#endif - LLONG prev_pts = ctx->current_pts; - ctx->current_pts = pts; - if (ctx->pts_set == 0) - ctx->pts_set = 1; - dbg_print(CCX_DMT_VIDES, "PTS: %s (%8u)", print_mstime_static(ctx->current_pts / (MPEG_CLOCK_FREQ / 1000)), - (unsigned)(ctx->current_pts)); - dbg_print(CCX_DMT_VIDES, " FTS: %s \n", print_mstime_static(ctx->fts_now)); - - // Check if PTS reset - if (ctx->current_pts < prev_pts) - { - ctx->pts_reset = 1; - } } int set_fts(struct ccx_common_timing_ctx *ctx) { -#ifndef DISABLE_RUST return ccxr_set_fts(ctx); -#endif - int pts_jump = 0; - - // ES don't have PTS unless GOP timing is used - if (!ctx->pts_set && ccx_common_timing_settings.is_elementary_stream) - return CCX_OK; - - // First check for timeline jump (only when min_pts was set (implies sync_pts)). - int dif = 0; - if (ctx->pts_set == 2) - { - dif = (int)(ctx->current_pts - ctx->sync_pts) / MPEG_CLOCK_FREQ; - - if (ccx_common_timing_settings.disable_sync_check) - { - // Disables sync check. Used for several input formats. - dif = 0; - } - - if (dif < -0.2 || dif >= max_dif) - { - // ATSC specs: More than 3501 ms means missing component - ccx_common_logging.log_ftn("\nWarning: Reference clock has changed abruptly (%d seconds filepos=%lld), attempting to synchronize\n", (int)dif, *ccx_common_timing_settings.file_position); - ccx_common_logging.log_ftn("Last sync PTS value: %lld\n", ctx->sync_pts); - ccx_common_logging.log_ftn("Current PTS value: %lld\n", ctx->current_pts); - ccx_common_logging.log_ftn("Note: You can disable this behavior by adding -ignoreptsjumps to the parameters.\n"); - pts_jump = 1; - pts_big_change = 1; - - // Discard the gap if it is not on an I-frame or temporal reference zero. - if (ctx->current_tref != 0 && ctx->current_picture_coding_type != CCX_FRAME_TYPE_I_FRAME) - { - ctx->fts_now = ctx->fts_max; - ccx_common_logging.log_ftn("Change did not occur on first frame - probably a broken GOP\n"); - return CCX_OK; - } - } - } - - // If min_pts was set just before a rollover we compensate by "roll-oving" it too - if (ctx->pts_set == 2 && !ctx->min_pts_adjusted) // min_pts set - { - // We want to be aware of the upcoming rollover, not after it happened, so we don't take - // the 3 most significant bits but the 3 next ones - uint64_t min_pts_big_bits = (ctx->min_pts >> 30) & 7; - uint64_t cur_pts_big_bits = (ctx->current_pts >> 30) & 7; - if (cur_pts_big_bits == 7 && !min_pts_big_bits) - { - // Huge difference possibly means the first min_pts was actually just over the boundary - // Take the current_pts (smaller, accounting for the rollover) instead - ctx->min_pts = ctx->current_pts; - ctx->min_pts_adjusted = 1; - } - else if (cur_pts_big_bits >= 1 && cur_pts_big_bits <= 6) // Far enough from the boundary - { - // Prevent the eventual difference with min_pts to make a bad adjustment - ctx->min_pts_adjusted = 1; - } - } - // Set min_pts, fts_offset - if (ctx->pts_set != 0) - { - ctx->pts_set = 2; - - // Use this part only the first time min_pts is set. Later treat - // it as a reference clock change - if (ctx->current_pts < ctx->min_pts && !pts_jump) - { - // If this is the first GOP, and seq 0 was not encountered yet - // we might reset min_pts/fts_offset again - - ctx->min_pts = ctx->current_pts; - - // Avoid next async test - ctx->sync_pts = (LLONG)(ctx->current_pts - ctx->current_tref * 1000.0 / current_fps * (MPEG_CLOCK_FREQ / 1000)); - - if (ctx->current_tref == 0) - { // Earliest time in GOP. - ctx->fts_offset = 0; - } - else if (total_frames_count - frames_since_ref_time == 0) - { // If this is the first frame (PES) there cannot be an offset. - // This part is also reached for dvr-ms/NTSC (RAW) as - // total_frames_count = frames_since_ref_time = 0 when - // this is called for the first time. - ctx->fts_offset = 0; - } - else - { // It needs to be "+1" because the current frame is - // not yet counted. - ctx->fts_offset = (LLONG)((total_frames_count - frames_since_ref_time + 1) * 1000.0 / current_fps); - } - ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nFirst sync time PTS: %s %+lldms (time before this PTS)\n", - print_mstime_static(ctx->min_pts / (MPEG_CLOCK_FREQ / 1000)), - ctx->fts_offset); - ccx_common_logging.debug_ftn(CCX_DMT_TIME, "Total_frames_count %u frames_since_ref_time %u\n", - total_frames_count, frames_since_ref_time); - } - - // -nosync disables syncing - if (pts_jump && !ccx_common_timing_settings.no_sync) - { - // The current time in the old time base is calculated using - // sync_pts (set at the beginning of the last GOP) plus the - // time of the frames since then. - ctx->fts_offset = ctx->fts_offset + (ctx->sync_pts - ctx->min_pts) / (MPEG_CLOCK_FREQ / 1000) + (LLONG)(frames_since_ref_time * 1000 / current_fps); - ctx->fts_max = ctx->fts_offset; - - // Start counting again from here - ctx->pts_set = 1; // Force min to be set again - ctx->sync_pts2fts_set = 0; // Make note of the new conversion values - - // Avoid next async test - the gap might have occured on - // current_tref != 0. - ctx->sync_pts = (LLONG)(ctx->current_pts - ctx->current_tref * 1000.0 / current_fps * (MPEG_CLOCK_FREQ / 1000)); - // Set min_pts = sync_pts as this is used for fts_now - ctx->min_pts = ctx->sync_pts; - - ccx_common_logging.debug_ftn(CCX_DMT_TIME, "\nNew min PTS time: %s %+lldms (time before this PTS)\n", - print_mstime_static(ctx->min_pts / (MPEG_CLOCK_FREQ / 1000)), - ctx->fts_offset); - } - } - - // Set sync_pts, fts_offset - if (ctx->current_tref == 0) - ctx->sync_pts = ctx->current_pts; - - // Reset counters - cb_field1 = 0; - cb_field2 = 0; - cb_708 = 0; - - // Avoid wrong "Calc. difference" and "Asynchronous by" numbers - // for uninitialized min_pts - if (1) // CFS: Remove or think decent condition - { - if (ctx->pts_set) - { - // If pts_set is TRUE we have min_pts - ctx->fts_now = (LLONG)((ctx->current_pts - ctx->min_pts) / (MPEG_CLOCK_FREQ / 1000) + ctx->fts_offset); - if (!ctx->sync_pts2fts_set) - { - ctx->sync_pts2fts_pts = ctx->current_pts; - ctx->sync_pts2fts_fts = ctx->fts_now; - ctx->sync_pts2fts_set = 1; - } - } - else - { - // No PTS info at all!! - ccx_common_logging.log_ftn("Set PTS called without any global timestamp set\n"); - return CCX_EINVAL; - } - } - if (ctx->fts_now > ctx->fts_max) - { - ctx->fts_max = ctx->fts_now; - } - - // If PTS resets, then fix minimum_fts and fts_max - if (ctx->pts_reset) - { - ctx->minimum_fts = 0; - ctx->fts_max = ctx->fts_now; - ctx->pts_reset = 0; - } - return CCX_OK; } LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field) { -#ifndef DISABLE_RUST return ccxr_get_fts(ctx, current_field); -#endif - - LLONG fts; - - switch (current_field) - { - case 1: - fts = ctx->fts_now + ctx->fts_global + cb_field1 * 1001 / 30; - break; - case 2: - fts = ctx->fts_now + ctx->fts_global + cb_field2 * 1001 / 30; - break; - case 3: - fts = ctx->fts_now + ctx->fts_global + cb_708 * 1001 / 30; - break; - default: - fatal(CCX_COMMON_EXIT_BUG_BUG, "get_fts: unhandled branch"); - } - // ccx_common_logging.debug_ftn(CCX_DMT_TIME, "[FTS] " - // "fts: %llu, fts_now: %llu, fts_global: %llu, current_field: %llu, cb_708: %llu\n", - // fts, fts_now, fts_global, current_field, cb_708); - return fts; } LLONG get_fts_max(struct ccx_common_timing_ctx *ctx) { -#ifndef DISABLE_RUST return ccxr_get_fts_max(ctx); -#endif - - // This returns the maximum FTS that belonged to a frame. Caption block - // counters are not applicable. - return ctx->fts_max + ctx->fts_global; } /** @@ -380,80 +161,21 @@ size_t print_mstime_buff(LLONG mstime, char *fmt, char *buf) char *print_mstime_static(LLONG mstime) { static char buf[15]; // 14 should be long enough - -#ifndef DISABLE_RUST return ccxr_print_mstime_static(mstime, buf); -#endif - - print_mstime_buff(mstime, "%02u:%02u:%02u:%03u", buf); - return buf; } /* Helper function for to display debug timing info. */ void print_debug_timing(struct ccx_common_timing_ctx *ctx) { -#ifndef DISABLE_RUST return ccxr_print_debug_timing(ctx); -#endif - - // Avoid wrong "Calc. difference" and "Asynchronous by" numbers - // for uninitialized min_pts - LLONG tempmin_pts = (ctx->min_pts == 0x01FFFFFFFFLL ? ctx->sync_pts : ctx->min_pts); - - ccx_common_logging.log_ftn("Sync time stamps: PTS: %s ", - print_mstime_static((ctx->sync_pts) / (MPEG_CLOCK_FREQ / 1000))); - ccx_common_logging.log_ftn("GOP: %s \n", print_mstime_static(gop_time.ms)); - - // Length first GOP to last GOP - LLONG goplenms = (LLONG)(gop_time.ms - first_gop_time.ms); - // Length at last sync point - LLONG ptslenms = (unsigned)((ctx->sync_pts - tempmin_pts) / (MPEG_CLOCK_FREQ / 1000) + ctx->fts_offset); - - ccx_common_logging.log_ftn("Last FTS: %s", - print_mstime_static(get_fts_max(ctx))); - ccx_common_logging.log_ftn(" GOP start FTS: %s\n", - print_mstime_static(fts_at_gop_start)); - - // Times are based on last GOP and/or sync time - ccx_common_logging.log_ftn("Max FTS diff. to PTS: %6lldms GOP: %6lldms\n\n", - get_fts_max(ctx) + (LLONG)(1000.0 / current_fps) - ptslenms, - get_fts_max(ctx) + (LLONG)(1000.0 / current_fps) - goplenms); } void calculate_ms_gop_time(struct gop_time_code *g) { -#ifndef DISABLE_RUST return ccxr_calculate_ms_gop_time(g); -#endif - - int seconds = (g->time_code_hours * 3600) + (g->time_code_minutes * 60) + g->time_code_seconds; - g->ms = (LLONG)(1000 * (seconds + g->time_code_pictures / current_fps)); - if (gop_rollover) - g->ms += 24 * 60 * 60 * 1000; } int gop_accepted(struct gop_time_code *g) { -#ifndef DISABLE_RUST return ccxr_gop_accepted(g); -#endif - - if (!((g->time_code_hours <= 23) && (g->time_code_minutes <= 59) && (g->time_code_seconds <= 59) && (g->time_code_pictures <= 59))) - return 0; - - if (gop_time.time_code_hours == 23 && gop_time.time_code_minutes == 59 && - g->time_code_hours == 0 && g->time_code_minutes == 0) - { - gop_rollover = 1; - return 1; - } - if (gop_time.inited) - { - if (gop_time.ms > g->ms) - { - // We are going back in time but it's not a complete day rollover - return 0; - } - } - return 1; } diff --git a/src/lib_ccx/ccx_decoders_708.c b/src/lib_ccx/ccx_decoders_708.c index 1af54a094..08b762e0b 100644 --- a/src/lib_ccx/ccx_decoders_708.c +++ b/src/lib_ccx/ccx_decoders_708.c @@ -824,27 +824,6 @@ void dtvcc_process_character(dtvcc_service_decoder *decoder, dtvcc_symbol symbol } } -void dtvcc_decoder_flush(dtvcc_ctx *dtvcc, dtvcc_service_decoder *decoder) -{ - ccx_common_logging.debug_ftn( - CCX_DMT_708, "[CEA-708] dtvcc_decoder_flush: Flushing decoder\n"); - int screen_content_changed = 0; - for (int i = 0; i < CCX_DTVCC_MAX_WINDOWS; i++) - { - dtvcc_window *window = &decoder->windows[i]; - if (window->visible) - { - screen_content_changed = 1; - dtvcc_window_update_time_hide(window, dtvcc->timing); - dtvcc_window_copy_to_screen(decoder, window); - window->visible = 0; - } - } - if (screen_content_changed) - dtvcc_screen_print(dtvcc, decoder); - dtvcc_write_done(decoder->tv, dtvcc->encoder); -} - //---------------------------------- COMMANDS ------------------------------------ void dtvcc_handle_CWx_SetCurrentWindow(dtvcc_service_decoder *decoder, int window_id) diff --git a/src/lib_ccx/ccx_decoders_708_encoding.c b/src/lib_ccx/ccx_decoders_708_encoding.c index b3d9508d4..471c92363 100644 --- a/src/lib_ccx/ccx_decoders_708_encoding.c +++ b/src/lib_ccx/ccx_decoders_708_encoding.c @@ -11,39 +11,3 @@ EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE) (there are several blank characters here, that's OK) A0-FF -> Group G1 as is - non-English characters and symbols */ - -#if defined(DISABLE_RUST) - -unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char) -{ - return g0_char; -} - -unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char) -{ - return g1_char; -} - -// TODO: Probably not right -// G2: Extended Control Code Set 1 -unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char) -{ - if (g2_char >= 0x20 && g2_char <= 0x3F) - return g2_char - (unsigned char)0x20; - if (g2_char >= 0x60 && g2_char <= 0x7F) - return g2_char + (unsigned char)0x20; - // Rest unmapped, so we return a blank space - return 0x20; -} - -// TODO: Probably not right -// G3: Future Characters and Icon Expansion -unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char) -{ - if (g3_char == 0xa0) // The "CC" (closed captions) sign - return 0x06; - // Rest unmapped, so we return a blank space - return 0x20; -} - -#endif diff --git a/src/lib_ccx/ccx_decoders_708_encoding.h b/src/lib_ccx/ccx_decoders_708_encoding.h index ef7ca2a84..2ea9961b3 100644 --- a/src/lib_ccx/ccx_decoders_708_encoding.h +++ b/src/lib_ccx/ccx_decoders_708_encoding.h @@ -3,16 +3,9 @@ #define CCX_DTVCC_MUSICAL_NOTE_CHAR 9836 // Unicode Character 'BEAMED SIXTEENTH NOTES' -#ifndef DISABLE_RUST extern unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char); extern unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char); extern unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char); extern unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char); -#else -unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char); -unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char); -unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char); -unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char); -#endif #endif /*_CCX_DECODERS_708_ENCODING_H_*/ diff --git a/src/lib_ccx/ccx_decoders_708_output.c b/src/lib_ccx/ccx_decoders_708_output.c index 5697ad242..5e403e514 100644 --- a/src/lib_ccx/ccx_decoders_708_output.c +++ b/src/lib_ccx/ccx_decoders_708_output.c @@ -4,7 +4,7 @@ #include "utility.h" #include "ccx_common_common.h" -#if !defined(DISABLE_RUST) && defined(WIN32) +#if defined(WIN32) extern void ccxr_close_handle(void *handle); #endif @@ -590,10 +590,8 @@ void dtvcc_writer_init(dtvcc_writer_ctx *writer, char *charset = cfg->all_services_charset ? cfg->all_services_charset : cfg->services_charsets[service_number - 1]; -#ifndef DISABLE_RUST writer->fhandle = NULL; writer->charset = charset; -#endif if (charset) { @@ -611,7 +609,7 @@ void dtvcc_writer_cleanup(dtvcc_writer_ctx *writer) { if (writer->fd >= 0 && writer->fd != STDOUT_FILENO) close(writer->fd); -#if !defined(DISABLE_RUST) && defined(WIN32) +#if defined(WIN32) ccxr_close_handle(writer->fhandle); writer->charset = NULL; #endif diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index 7961506f6..8316ccd07 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -15,10 +15,8 @@ made to reuse, not duplicate, as many functions as possible */ #include "ccx_encoders_mcc.h" #include "ccx_dtvcc.h" -#ifndef DISABLE_RUST extern int ccxr_process_cc_data(struct lib_cc_decode *dec_ctx, unsigned char *cc_data, int cc_count); extern void ccxr_flush_decoder(struct dtvcc_ctx *dtvcc, struct dtvcc_service_decoder *decoder); -#endif uint64_t utc_refvalue = UINT64_MAX; /* _UI64_MAX/UINT64_MAX means don't use UNIX, 0 = use current system time as reference, +1 use a specific reference */ extern int in_xds_mode; @@ -54,9 +52,7 @@ int process_cc_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, return 0; } -#ifndef DISABLE_RUST ret = ccxr_process_cc_data(dec_ctx, cc_data, cc_count); -#endif for (int j = 0; j < cc_count * 3; j = j + 3) { @@ -198,18 +194,7 @@ int do_cb(struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle } if (timeok) { - if (ctx->write_format != CCX_OF_RCWT) - { -#ifdef DISABLE_RUST - char temp[4]; - temp[0] = cc_valid; - temp[1] = cc_type; - temp[2] = cc_block[1]; - temp[3] = cc_block[2]; - dtvcc_process_data(ctx->dtvcc, (const unsigned char *)temp); -#endif - } - else + if (ctx->write_format == CCX_OF_RCWT) writercwtdata(ctx, cc_block, sub); } cb_708++; @@ -451,11 +436,7 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub) if (decoder->cc_count > 0) { ctx->current_field = 3; -#ifndef DISABLE_RUST ccxr_flush_decoder(ctx->dtvcc, decoder); -#else - dtvcc_decoder_flush(ctx->dtvcc, decoder); -#endif } } } diff --git a/src/lib_ccx/ccx_encoders_common.c b/src/lib_ccx/ccx_encoders_common.c index 3196d3500..7cb69e9a5 100644 --- a/src/lib_ccx/ccx_encoders_common.c +++ b/src/lib_ccx/ccx_encoders_common.c @@ -16,10 +16,8 @@ int fsync(int fd) } #endif -#ifndef DISABLE_RUST int ccxr_get_str_basic(unsigned char *out_buffer, unsigned char *in_buffer, int trim_subs, enum ccx_encoding_type in_enc, enum ccx_encoding_type out_enc, int max_len); -#endif // 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 = { @@ -118,223 +116,10 @@ void find_limit_characters(const unsigned char *line, int *first_non_blank, int } } -unsigned int utf8_to_latin1_map(const unsigned int code) -{ - /* Code points 0 to U+00FF are the same in both. */ - if (code < 256U) - return code; - - switch (code) - { - case 0x0152U: - return 188U; /* U+0152 = 0xBC: OE ligature */ - case 0x0153U: - return 189U; /* U+0153 = 0xBD: oe ligature */ - case 0x0160U: - return 166U; /* U+0160 = 0xA6: S with caron */ - case 0x0161U: - return 168U; /* U+0161 = 0xA8: s with caron */ - case 0x0178U: - return 190U; /* U+0178 = 0xBE: Y with diaresis */ - case 0x017DU: - return 180U; /* U+017D = 0xB4: Z with caron */ - case 0x017EU: - return 184U; /* U+017E = 0xB8: z with caron */ - case 0x20ACU: - return 164U; /* U+20AC = 0xA4: Euro */ - default: - return 256U; - } -} - -int change_utf8_encoding(unsigned char *dest, unsigned char *src, int len, enum ccx_encoding_type out_enc) -{ - unsigned char *orig = dest; // Keep for calculating length - unsigned char *orig_src = src; // Keep for calculating length - for (int i = 0; src < orig_src + len;) - { - unsigned char c = src[i]; - int c_len = 0; - - if (c < 0x80) - c_len = 1; - else if ((c & 0x20) == 0) - c_len = 2; - else if ((c & 0x10) == 0) - c_len = 3; - else if ((c & 0x08) == 0) - c_len = 4; - else if ((c & 0x04) == 0) - c_len = 5; - - switch (out_enc) - { - case CCX_ENC_UTF_8: - memcpy(dest, src, len); - return len; - case CCX_ENC_LATIN_1: - if (c_len == 1) - *dest++ = *src; - else if (c_len == 2) - { - if ((src[1] & 0x40) == 0) - { - int cp = utf8_to_latin1_map((((unsigned int)(src[0] & 0x1F)) << 6) | ((unsigned int)(src[1] & 0x3F))); - if (cp < 256) - *dest++ = cp; - else - *dest++ = '?'; - } - else - *dest++ = '?'; - } - else if (c_len == 3) - { - if ((src[1] & 0x40) == 0 && (src[2] & 0x40) == 0) - { - int cp = utf8_to_latin1_map((((unsigned int)(src[0] & 0x0F)) << 12) | (((unsigned int)(src[1] & 0x3F)) << 6) | ((unsigned int)(src[2] & 0x3F))); - if (cp < 256) - *dest++ = cp; - else - *dest++ = '?'; - } - } - else if (c_len == 4) - { - if ((src[1] & 0x40) == 0 && - (src[2] & 0x40) == 0 && - (src[3] & 0x40) == 0) - { - int cp = utf8_to_latin1_map((((unsigned int)(src[0] & 0x07)) << 18) | (((unsigned int)(src[1] & 0x3F)) << 12) | (((unsigned int)(src[2] & 0x3F)) << 6) | ((unsigned int)(src[3] & 0x3F))); - if (cp < 256) - *(dest++) = cp; - else - *dest++ = '?'; - } - else - *dest++ = '?'; - } - else if (c_len == 5) - { - if ((src[1] & 0x40) == 0 && - (src[2] & 0x40) == 0 && - (src[3] & 0x40) == 0 && - (src[4] & 0x40) == 0) - { - int cp = utf8_to_latin1_map((((unsigned int)(src[0] & 0x03)) << 24U) | (((unsigned int)(src[1] & 0x3F)) << 18U) | (((unsigned int)(src[2] & 0x3F)) << 12U) | (((unsigned int)(src[3] & 0x3F)) << 6U) | ((unsigned int)(src[4] & 0x3FU))); - if (cp < 256) - *(dest++) = cp; - else - *dest++ = '?'; - } - else - *dest++ = '?'; - } - else - *dest++ = '?'; - break; - case CCX_ENC_UNICODE: - return CCX_ENOSUPP; - case CCX_ENC_ASCII: - if (c_len == 1) - *dest++ = *src; - else - *dest++ = '?'; - default: - return CCX_ENOSUPP; - } - src += c_len; - } - *dest = 0; - return (dest - orig); // Return length -} - -int change_latin1_encoding(unsigned char *dest, unsigned char *src, int len, enum ccx_encoding_type out_enc) -{ - return CCX_ENOSUPP; -} - -int change_unicode_encoding(unsigned char *dest, unsigned char *src, int len, enum ccx_encoding_type out_enc) -{ - return CCX_ENOSUPP; -} - -int change_ascii_encoding(unsigned char *dest, unsigned char *src, int len, enum ccx_encoding_type out_enc) -{ - unsigned char *orig = dest; // Keep for calculating length - int bytes = 0; - for (int i = 0; i < len; i++) - { - char c = src[i]; - switch (out_enc) - { - case CCX_ENC_UTF_8: - bytes = get_char_in_utf_8(dest, c); - break; - case CCX_ENC_LATIN_1: - get_char_in_latin_1(dest, c); - bytes = 1; - break; - case CCX_ENC_UNICODE: - get_char_in_unicode(dest, c); - bytes = 2; - break; - case CCX_ENC_ASCII: - memcpy(dest, src, len); - return len; - default: - return CCX_ENOSUPP; - } - dest += bytes; - } - *dest = 0; - return (dest - orig); // Return length -} - int get_str_basic(unsigned char *out_buffer, unsigned char *in_buffer, int trim_subs, enum ccx_encoding_type in_enc, enum ccx_encoding_type out_enc, int max_len) { -#ifndef DISABLE_RUST return ccxr_get_str_basic(out_buffer, in_buffer, trim_subs, in_enc, out_enc, max_len); -#else - int last_non_blank = -1; - int first_non_blank = -1; - int len = 0; - find_limit_characters(in_buffer, &first_non_blank, &last_non_blank, max_len); - if (!trim_subs) - first_non_blank = 0; - - if (first_non_blank == -1) - { - *out_buffer = 0; - return 0; - } - // change encoding only when required - switch (in_enc) - { - case CCX_ENC_UTF_8: - len = change_utf8_encoding(out_buffer, in_buffer + first_non_blank, last_non_blank - first_non_blank + 1, out_enc); - break; - case CCX_ENC_LATIN_1: - len = change_latin1_encoding(out_buffer, in_buffer + first_non_blank, last_non_blank - first_non_blank + 1, out_enc); - break; - case CCX_ENC_UNICODE: - len = change_unicode_encoding(out_buffer, in_buffer + first_non_blank, last_non_blank - first_non_blank + 1, out_enc); - break; - case CCX_ENC_ASCII: - len = change_ascii_encoding(out_buffer, in_buffer + first_non_blank, last_non_blank - first_non_blank + 1, out_enc); - break; - } - if (len < 0) - mprint("WARNING: Could not encode in specified format\n"); - else if (len == CCX_ENOSUPP) - // we only support ASCII to other encoding std - mprint("WARNING: Encoding is not yet supported\n"); - else - return (unsigned)len; // Return length - - return 0; // Return length -#endif } int write_subtitle_file_footer(struct encoder_ctx *ctx, struct ccx_s_write *out) @@ -873,10 +658,8 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg) if (!cfg->services_enabled[i]) { ctx->dtvcc_writers[i].fd = -1; -#ifndef DISABLE_RUST ctx->dtvcc_writers[i].fhandle = NULL; ctx->dtvcc_writers[i].charset = NULL; -#endif ctx->dtvcc_writers[i].filename = NULL; ctx->dtvcc_writers[i].cd = (iconv_t)-1; continue; @@ -885,10 +668,8 @@ static int init_output_ctx(struct encoder_ctx *ctx, struct encoder_cfg *cfg) if (cfg->cc_to_stdout) { ctx->dtvcc_writers[i].fd = STDOUT_FILENO; -#ifndef DISABLE_RUST ctx->dtvcc_writers[i].fhandle = NULL; ctx->dtvcc_writers[i].charset = NULL; -#endif ctx->dtvcc_writers[i].filename = NULL; ctx->dtvcc_writers[i].cd = (iconv_t)-1; } diff --git a/src/lib_ccx/ccx_encoders_common.h b/src/lib_ccx/ccx_encoders_common.h index 5ddd324d9..b8b51bdf6 100644 --- a/src/lib_ccx/ccx_encoders_common.h +++ b/src/lib_ccx/ccx_encoders_common.h @@ -24,12 +24,10 @@ if (ctx->buffer == NULL) { fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory for typedef struct dtvcc_writer_ctx { int fd; -#ifndef DISABLE_RUST // File handle used to work with files on windows void *fhandle; // Charset of the subtitle char *charset; -#endif char *filename; iconv_t cd; } dtvcc_writer_ctx; diff --git a/src/lib_ccx/hardsubx_classifier.c b/src/lib_ccx/hardsubx_classifier.c index 21294413d..eed075984 100644 --- a/src/lib_ccx/hardsubx_classifier.c +++ b/src/lib_ccx/hardsubx_classifier.c @@ -1,346 +1,2 @@ #include "lib_ccx.h" #include "utility.h" - -#if defined(ENABLE_HARDSUBX) && defined(DISABLE_RUST) -// TODO: Correct FFMpeg integration -#include -#include -#include -#include -#include -#include "hardsubx.h" - -char *get_ocr_text_simple(struct lib_hardsubx_ctx *ctx, PIX *image) -{ - char *text_out = NULL; - - TessBaseAPISetImage2(ctx->tess_handle, image); - if (TessBaseAPIRecognize(ctx->tess_handle, NULL) != 0) - { - mprint("Error in Tesseract recognition, skipping frame\n"); - return NULL; - } - - if ((text_out = TessBaseAPIGetUTF8Text(ctx->tess_handle)) == NULL) - { - mprint("Error getting text, skipping frame\n"); - } - return text_out; -} - -char *get_ocr_text_wordwise(struct lib_hardsubx_ctx *ctx, PIX *image) -{ - char *text_out = NULL; - - TessBaseAPISetImage2(ctx->tess_handle, image); - if (TessBaseAPIRecognize(ctx->tess_handle, NULL) != 0) - { - mprint("Error in Tesseract recognition, skipping word\n"); - return NULL; - } - - TessResultIterator *it = TessBaseAPIGetIterator(ctx->tess_handle); - TessPageIteratorLevel level = RIL_WORD; - - int prev_ital = 0; - - if (it != 0) - { - do - { - char *word; - char *ts_word = TessResultIteratorGetUTF8Text(it, level); - if (ts_word == NULL || strlen(ts_word) == 0) - continue; - word = strdup(ts_word); - TessDeleteText(ts_word); - if (text_out == NULL) - { - if (ctx->detect_italics) - { - int italic = 0; - int dummy = 0; - TessResultIteratorWordFontAttributes(it, &dummy, &italic, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy); - if (italic == 1 && prev_ital == 0) - { - char *word_copy = strdup(word); - word = realloc(word, strlen(word) + strlen("") + 2); - strcpy(word, ""); - strcat(word, word_copy); - free(word_copy); - prev_ital = 1; - } - else if (italic == 0 && prev_ital == 1) - { - word = realloc(word, strlen(word) + strlen("") + 2); - strcat(word, ""); - prev_ital = 0; - } - } - text_out = strdup(word); - text_out = realloc(text_out, strlen(text_out) + 2); - strcat(text_out, " "); - continue; - } - if (ctx->detect_italics) - { - int italic = 0; - int dummy = 0; - TessResultIteratorWordFontAttributes(it, &dummy, &italic, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy); - if (italic == 1 && prev_ital == 0) - { - char *word_copy = strdup(word); - word = realloc(word, strlen(word) + strlen("") + 2); - strcpy(word, ""); - strcat(word, word_copy); - free(word_copy); - prev_ital = 1; - } - else if (italic == 0 && prev_ital == 1) - { - word = realloc(word, strlen(word) + strlen("") + 2); - strcat(word, ""); - prev_ital = 0; - } - } - text_out = realloc(text_out, strlen(text_out) + strlen(word) + 2); - strcat(text_out, word); - strcat(text_out, " "); - free(word); - } while (TessPageIteratorNext((TessPageIterator *)it, level)); - } - - if (ctx->detect_italics && prev_ital == 1) - { - text_out = realloc(text_out, strlen(text_out) + strlen("") + 2); - strcat(text_out, ""); - } - - TessResultIteratorDelete(it); - - return text_out; -} - -char *get_ocr_text_letterwise(struct lib_hardsubx_ctx *ctx, PIX *image) -{ - char *text_out = NULL; - - TessBaseAPISetImage2(ctx->tess_handle, image); - if (TessBaseAPIRecognize(ctx->tess_handle, NULL) != 0) - { - mprint("Error in Tesseract recognition, skipping symbol\n"); - return NULL; - } - - TessResultIterator *it = TessBaseAPIGetIterator(ctx->tess_handle); - TessPageIteratorLevel level = RIL_SYMBOL; - - if (it != 0) - { - do - { - char *letter; - char *ts_letter = TessResultIteratorGetUTF8Text(it, level); - if (ts_letter == NULL || strlen(ts_letter) == 0) - continue; - letter = strdup(ts_letter); - TessDeleteText(ts_letter); - if (text_out == NULL) - { - text_out = strdup(letter); - continue; - } - text_out = realloc(text_out, strlen(text_out) + strlen(letter) + 1); - strcat(text_out, letter); - free(letter); - } while (TessPageIteratorNext((TessPageIterator *)it, level)); - } - - TessResultIteratorDelete(it); - - return text_out; -} - -char *get_ocr_text_simple_threshold(struct lib_hardsubx_ctx *ctx, PIX *image, float threshold) -{ - char *text_out = NULL; - - TessBaseAPISetImage2(ctx->tess_handle, image); - if (TessBaseAPIRecognize(ctx->tess_handle, NULL) != 0) - { - mprint("Error in Tesseract recognition, skipping frame\n"); - return NULL; - } - - if ((text_out = TessBaseAPIGetUTF8Text(ctx->tess_handle)) == NULL) - { - mprint("Error getting text, skipping frame\n"); - } - - int conf = TessBaseAPIMeanTextConf(ctx->tess_handle); - - if (conf < threshold) - return NULL; - - ctx->cur_conf = (float)conf; - - return text_out; -} - -char *get_ocr_text_wordwise_threshold(struct lib_hardsubx_ctx *ctx, PIX *image, float threshold) -{ - char *text_out = NULL; - - TessBaseAPISetImage2(ctx->tess_handle, image); - if (TessBaseAPIRecognize(ctx->tess_handle, NULL) != 0) - { - mprint("Error in Tesseract recognition, skipping word\n"); - return NULL; - } - - TessResultIterator *it = TessBaseAPIGetIterator(ctx->tess_handle); - TessPageIteratorLevel level = RIL_WORD; - - int prev_ital = 0; - float total_conf = 0.0; - int num_words = 0; - - if (it != 0) - { - do - { - char *word; - char *ts_word = TessResultIteratorGetUTF8Text(it, level); - if (ts_word == NULL || strlen(ts_word) == 0) - continue; - word = strdup(ts_word); - TessDeleteText(ts_word); - float conf = TessResultIteratorConfidence(it, level); - if (conf < threshold) - continue; - total_conf += conf; - num_words++; - if (text_out == NULL) - { - if (ctx->detect_italics) - { - int italic = 0; - int dummy = 0; - TessResultIteratorWordFontAttributes(it, &dummy, &italic, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy); - if (italic == 1 && prev_ital == 0) - { - char *word_copy = strdup(word); - word = realloc(word, strlen(word) + strlen("") + 2); - strcpy(word, ""); - strcat(word, word_copy); - free(word_copy); - prev_ital = 1; - } - else if (italic == 0 && prev_ital == 1) - { - word = realloc(word, strlen(word) + strlen("") + 2); - strcat(word, ""); - prev_ital = 0; - } - } - text_out = strdup(word); - text_out = realloc(text_out, strlen(text_out) + 2); - strcat(text_out, " "); - continue; - } - if (ctx->detect_italics) - { - int italic = 0; - int dummy = 0; - TessResultIteratorWordFontAttributes(it, &dummy, &italic, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy); - if (italic == 1 && prev_ital == 0) - { - char *word_copy = strdup(word); - word = realloc(word, strlen(word) + strlen("") + 2); - strcpy(word, ""); - strcat(word, word_copy); - free(word_copy); - prev_ital = 1; - } - else if (italic == 0 && prev_ital == 1) - { - word = realloc(word, strlen(word) + strlen("") + 2); - strcat(word, ""); - prev_ital = 0; - } - } - text_out = realloc(text_out, strlen(text_out) + strlen(word) + 2); - strcat(text_out, word); - strcat(text_out, " "); - free(word); - } while (TessPageIteratorNext((TessPageIterator *)it, level)); - } - - if (ctx->detect_italics && prev_ital == 1) - { - text_out = realloc(text_out, strlen(text_out) + strlen("") + 2); - strcat(text_out, ""); - } - - if (num_words > 0) - total_conf = total_conf / num_words; - ctx->cur_conf = total_conf; - - TessResultIteratorDelete(it); - - return text_out; -} - -char *get_ocr_text_letterwise_threshold(struct lib_hardsubx_ctx *ctx, PIX *image, float threshold) -{ - char *text_out = NULL; - - TessBaseAPISetImage2(ctx->tess_handle, image); - if (TessBaseAPIRecognize(ctx->tess_handle, NULL) != 0) - { - mprint("Error in Tesseract recognition, skipping symbol\n"); - return NULL; - } - - TessResultIterator *it = TessBaseAPIGetIterator(ctx->tess_handle); - TessPageIteratorLevel level = RIL_SYMBOL; - - float total_conf = 0.0; - int num_words = 0; - - if (it != 0) - { - do - { - char *letter; - char *ts_letter = TessResultIteratorGetUTF8Text(it, level); - if (ts_letter == NULL || strlen(ts_letter) == 0) - continue; - letter = strdup(ts_letter); - TessDeleteText(ts_letter); - float conf = TessResultIteratorConfidence(it, level); - if (conf < threshold) - continue; - total_conf += conf; - num_words++; - if (text_out == NULL) - { - text_out = strdup(letter); - continue; - } - text_out = realloc(text_out, strlen(text_out) + strlen(letter) + 1); - strcat(text_out, letter); - free(letter); - } while (TessPageIteratorNext((TessPageIterator *)it, level)); - } - - if (num_words > 0) - total_conf = total_conf / num_words; - ctx->cur_conf = total_conf; - - TessResultIteratorDelete(it); - - return text_out; -} - -#endif diff --git a/src/lib_ccx/hardsubx_decoder.c b/src/lib_ccx/hardsubx_decoder.c index 43a7a09fc..9a40995a5 100644 --- a/src/lib_ccx/hardsubx_decoder.c +++ b/src/lib_ccx/hardsubx_decoder.c @@ -14,212 +14,6 @@ #include "ffmpeg_intgr.h" #endif -#ifdef DISABLE_RUST -char *_process_frame_white_basic(struct lib_hardsubx_ctx *ctx, AVFrame *frame, int width, int height, int index) -{ - // printf("frame : %04d\n", index); - PIX *im; - PIX *gray_im; - PIX *sobel_edge_im; - PIX *dilate_gray_im; - PIX *edge_im; - PIX *lum_im; - PIX *feat_im; - char *subtitle_text; - - subtitle_text = NULL; - im = pixCreate(width, height, 32); - lum_im = pixCreate(width, height, 32); - feat_im = pixCreate(width, height, 32); - - for (int i = (3 * height) / 4; i < height; i++) - { - for (int j = 0; j < width; j++) - { - int p = j * 3 + i * frame->linesize[0]; - int r = frame->data[0][p]; - int g = frame->data[0][p + 1]; - int b = frame->data[0][p + 2]; - pixSetRGBPixel(im, j, i, r, g, b); - float L, A, B; - rgb_to_lab((float)r, (float)g, (float)b, &L, &A, &B); - if (L > ctx->lum_thresh) - pixSetRGBPixel(lum_im, j, i, 255, 255, 255); - else - pixSetRGBPixel(lum_im, j, i, 0, 0, 0); - } - } - - // Handle the edge image - gray_im = pixConvertRGBToGray(im, 0.0, 0.0, 0.0); - sobel_edge_im = pixSobelEdgeFilter(gray_im, L_VERTICAL_EDGES); - dilate_gray_im = pixDilateGray(sobel_edge_im, 21, 11); - edge_im = pixThresholdToBinary(dilate_gray_im, 50); - - for (int i = 3 * (height / 4); i < height; i++) - { - for (int j = 0; j < width; j++) - { - unsigned int p1, p2, p3; - pixGetPixel(edge_im, j, i, &p1); - // pixGetPixel(pixd,j,i,&p2); - pixGetPixel(lum_im, j, i, &p3); - if (p1 == 0 && p3 > 0) - pixSetRGBPixel(feat_im, j, i, 255, 255, 255); - else - pixSetRGBPixel(feat_im, j, i, 0, 0, 0); - } - } - - if (ctx->detect_italics) - { - ctx->ocr_mode = HARDSUBX_OCRMODE_WORD; - } - - // TESSERACT OCR FOR THE FRAME HERE - switch (ctx->ocr_mode) - { - case HARDSUBX_OCRMODE_WORD: - if (ctx->conf_thresh > 0) - subtitle_text = get_ocr_text_wordwise_threshold(ctx, feat_im, ctx->conf_thresh); - else - subtitle_text = get_ocr_text_wordwise(ctx, feat_im); - break; - case HARDSUBX_OCRMODE_LETTER: - if (ctx->conf_thresh > 0) - subtitle_text = get_ocr_text_letterwise_threshold(ctx, feat_im, ctx->conf_thresh); - else - subtitle_text = get_ocr_text_letterwise(ctx, feat_im); - break; - case HARDSUBX_OCRMODE_FRAME: - if (ctx->conf_thresh > 0) - subtitle_text = get_ocr_text_simple_threshold(ctx, feat_im, ctx->conf_thresh); - else - subtitle_text = get_ocr_text_simple(ctx, feat_im); - break; - default: - fatal(EXIT_MALFORMED_PARAMETER, "Invalid OCR Mode"); - } - - pixDestroy(&im); - pixDestroy(&gray_im); - pixDestroy(&sobel_edge_im); - pixDestroy(&dilate_gray_im); - pixDestroy(&edge_im); - pixDestroy(&lum_im); - pixDestroy(&feat_im); - - return subtitle_text; -} - -char *_process_frame_color_basic(struct lib_hardsubx_ctx *ctx, AVFrame *frame, int width, int height, int index) -{ - PIX *im; - PIX *hue_im; - PIX *gray_im; - PIX *sobel_edge_im; - PIX *dilate_gray_im; - PIX *edge_im; - PIX *gray_im_2; - PIX *edge_im_2; - PIX *pixd; - PIX *feat_im; - char *subtitle_text = NULL; - - im = pixCreate(width, height, 32); - hue_im = pixCreate(width, height, 32); - subtitle_text = NULL; - - for (int i = 0; i < height; i++) - { - for (int j = 0; j < width; j++) - { - int p = j * 3 + i * frame->linesize[0]; - int r = frame->data[0][p]; - int g = frame->data[0][p + 1]; - int b = frame->data[0][p + 2]; - pixSetRGBPixel(im, j, i, r, g, b); - float H, S, V; - rgb_to_hsv((float)r, (float)g, (float)b, &H, &S, &V); - if (fabsf(H - ctx->hue) < 20) - { - pixSetRGBPixel(hue_im, j, i, r, g, b); - } - } - } - - gray_im = pixConvertRGBToGray(im, 0.0, 0.0, 0.0); - sobel_edge_im = pixSobelEdgeFilter(gray_im, L_VERTICAL_EDGES); - dilate_gray_im = pixDilateGray(sobel_edge_im, 21, 1); - edge_im = pixThresholdToBinary(dilate_gray_im, 50); - - gray_im_2 = pixConvertRGBToGray(hue_im, 0.0, 0.0, 0.0); - edge_im_2 = pixDilateGray(gray_im_2, 5, 5); - - pixSauvolaBinarize(gray_im_2, 15, 0.3, 1, NULL, NULL, NULL, &pixd); - - feat_im = pixCreate(width, height, 32); - for (int i = 3 * (height / 4); i < height; i++) - { - for (int j = 0; j < width; j++) - { - unsigned int p1, p2, p3, p4; - pixGetPixel(edge_im, j, i, &p1); - pixGetPixel(pixd, j, i, &p2); - // pixGetPixel(hue_im,j,i,&p3); - pixGetPixel(edge_im_2, j, i, &p4); - if (p1 == 0 && p2 == 0 && p4 > 0) // if(p4>0&&p1==0)//if(p2==0&&p1==0&&p3>0) - { - pixSetRGBPixel(feat_im, j, i, 255, 255, 255); - } - } - } - - if (ctx->detect_italics) - { - ctx->ocr_mode = HARDSUBX_OCRMODE_WORD; - } - - // TESSERACT OCR FOR THE FRAME HERE - switch (ctx->ocr_mode) - { - case HARDSUBX_OCRMODE_WORD: - if (ctx->conf_thresh > 0) - subtitle_text = get_ocr_text_wordwise_threshold(ctx, feat_im, ctx->conf_thresh); - else - subtitle_text = get_ocr_text_wordwise(ctx, feat_im); - break; - case HARDSUBX_OCRMODE_LETTER: - if (ctx->conf_thresh > 0) - subtitle_text = get_ocr_text_letterwise_threshold(ctx, feat_im, ctx->conf_thresh); - else - subtitle_text = get_ocr_text_letterwise(ctx, feat_im); - break; - case HARDSUBX_OCRMODE_FRAME: - if (ctx->conf_thresh > 0) - subtitle_text = get_ocr_text_simple_threshold(ctx, feat_im, ctx->conf_thresh); - else - subtitle_text = get_ocr_text_simple(ctx, feat_im); - break; - default: - fatal(EXIT_MALFORMED_PARAMETER, "Invalid OCR Mode"); - } - - pixDestroy(&im); - pixDestroy(&hue_im); - pixDestroy(&gray_im); - pixDestroy(&sobel_edge_im); - pixDestroy(&dilate_gray_im); - pixDestroy(&edge_im); - pixDestroy(&gray_im_2); - pixDestroy(&edge_im_2); - pixDestroy(&pixd); - pixDestroy(&feat_im); - - return subtitle_text; -} -#endif - void _display_frame(struct lib_hardsubx_ctx *ctx, AVFrame *frame, int width, int height, int timestamp) { // Debug: Display the frame after processing @@ -299,82 +93,6 @@ void _display_frame(struct lib_hardsubx_ctx *ctx, AVFrame *frame, int width, int pixDestroy(&feat_im); } -#ifdef DISABLE_RUST -char *_process_frame_tickertext(struct lib_hardsubx_ctx *ctx, AVFrame *frame, int width, int height, int index) -{ - PIX *im; - PIX *gray_im; - PIX *sobel_edge_im; - PIX *dilate_gray_im; - PIX *edge_im; - PIX *lum_im; - PIX *feat_im; - char *subtitle_text; - - subtitle_text = NULL; - im = pixCreate(width, height, 32); - lum_im = pixCreate(width, height, 32); - feat_im = pixCreate(width, height, 32); - - for (int i = (92 * height) / 100; i < height; i++) - { - for (int j = 0; j < width; j++) - { - int p = j * 3 + i * frame->linesize[0]; - int r = frame->data[0][p]; - int g = frame->data[0][p + 1]; - int b = frame->data[0][p + 2]; - pixSetRGBPixel(im, j, i, r, g, b); - float L, A, B; - rgb_to_lab((float)r, (float)g, (float)b, &L, &A, &B); - if (L > ctx->lum_thresh) - pixSetRGBPixel(lum_im, j, i, 255, 255, 255); - else - pixSetRGBPixel(lum_im, j, i, 0, 0, 0); - } - } - - // Handle the edge image - gray_im = pixConvertRGBToGray(im, 0.0, 0.0, 0.0); - sobel_edge_im = pixSobelEdgeFilter(gray_im, L_VERTICAL_EDGES); - dilate_gray_im = pixDilateGray(sobel_edge_im, 21, 11); - edge_im = pixThresholdToBinary(dilate_gray_im, 50); - - for (int i = 92 * (height / 100); i < height; i++) - { - for (int j = 0; j < width; j++) - { - unsigned int p1, p2, p3; - pixGetPixel(edge_im, j, i, &p1); - // pixGetPixel(pixd,j,i,&p2); - pixGetPixel(lum_im, j, i, &p3); - if (p1 == 0 && p3 > 0) - pixSetRGBPixel(feat_im, j, i, 255, 255, 255); - else - pixSetRGBPixel(feat_im, j, i, 0, 0, 0); - } - } - - // Tesseract OCR for the ticker text here - subtitle_text = get_ocr_text_simple(ctx, lum_im); - char write_path[100]; - sprintf(write_path, "./lum_im%04d.jpg", index); - pixWrite(write_path, lum_im, IFF_JFIF_JPEG); - sprintf(write_path, "./im%04d.jpg", index); - pixWrite(write_path, im, IFF_JFIF_JPEG); - - pixDestroy(&im); - pixDestroy(&gray_im); - pixDestroy(&sobel_edge_im); - pixDestroy(&dilate_gray_im); - pixDestroy(&edge_im); - pixDestroy(&lum_im); - pixDestroy(&feat_im); - - return subtitle_text; -} -#endif - int hardsubx_process_frames_tickertext(struct lib_hardsubx_ctx *ctx, struct encoder_ctx *enc_ctx) { // Search for ticker text at the bottom of the screen, such as in Russia TV1 or stock prices diff --git a/src/lib_ccx/hardsubx_imgops.c b/src/lib_ccx/hardsubx_imgops.c index 0c3757b06..eed075984 100644 --- a/src/lib_ccx/hardsubx_imgops.c +++ b/src/lib_ccx/hardsubx_imgops.c @@ -1,116 +1,2 @@ #include "lib_ccx.h" #include "utility.h" - -#if defined(ENABLE_HARDSUBX) && defined(DISABLE_RUST) -// TODO: Correct FFMpeg integration -#include -#include -#include -#include -#include -#include "hardsubx.h" - -#define BLACK 20.0 -#define YELLOW 70.0 - -#define min_f(a, b, c) (fminf(a, fminf(b, c))) -#define max_f(a, b, c) (fmaxf(a, fmaxf(b, c))) - -void rgb_to_hsv(float R, float G, float B, float *H, float *S, float *V) -{ - // Conversion into HSV color space to get Hue - float r = R / 255.0f; - float g = G / 255.0f; - float b = B / 255.0f; - - float h, s, v; // h:0-360.0, s:0.0-1.0, v:0.0-1.0 - - float max = max_f(r, g, b); - float min = min_f(r, g, b); - - v = max; - - if (max == 0.0f) - { - s = 0; - h = 0; - } - else if (max - min == 0.0f) - { - s = 0; - h = 0; - } - else - { - s = (max - min) / max; - - if (max == r) - { - h = 60 * ((g - b) / (max - min)) + 0; - } - else if (max == g) - { - h = 60 * ((b - r) / (max - min)) + 120; - } - else - { - h = 60 * ((r - g) / (max - min)) + 240; - } - } - - if (h < 0) - h += 360.0f; - - *H = (unsigned char)(h); // dst_h : 0-360 - *S = (unsigned char)(s * 255); // dst_s : 0-255 - *V = (unsigned char)(v * 255); // dst_v : 0-255 -} - -void rgb_to_lab(float R, float G, float B, float *L, float *a, float *b) -{ - // Conversion to the CIE-LAB color space to get the Luminance - float X, Y, Z, fX, fY, fZ; - - X = 0.412453 * R + 0.357580 * G + 0.180423 * B; - Y = 0.212671 * R + 0.715160 * G + 0.072169 * B; - Z = 0.019334 * R + 0.119193 * G + 0.950227 * B; - - X /= (255 * 0.950456); - Y /= 255; - Z /= (255 * 1.088754); - - if (Y > 0.008856) - { - fY = pow(Y, 1.0 / 3.0); - *L = 116.0 * fY - 16.0; - } - else - { - fY = 7.787 * Y + 16.0 / 116.0; - *L = 903.3 * Y; - } - - if (X > 0.008856) - fX = pow(X, 1.0 / 3.0); - else - fX = 7.787 * X + 16.0 / 116.0; - - if (Z > 0.008856) - fZ = pow(Z, 1.0 / 3.0); - else - fZ = 7.787 * Z + 16.0 / 116.0; - - *a = 500.0 * (fX - fY); - *b = 200.0 * (fY - fZ); - - if (*L < BLACK) - { - *a *= exp((*L - BLACK) / (BLACK / 4)); - *b *= exp((*L - BLACK) / (BLACK / 4)); - *L = BLACK; - } - if (*b > YELLOW) - *b = YELLOW; -} - -#endif diff --git a/src/lib_ccx/hardsubx_utility.c b/src/lib_ccx/hardsubx_utility.c index 2a8894379..eed075984 100644 --- a/src/lib_ccx/hardsubx_utility.c +++ b/src/lib_ccx/hardsubx_utility.c @@ -1,132 +1,2 @@ #include "lib_ccx.h" #include "utility.h" - -#if defined(ENABLE_HARDSUBX) && defined(DISABLE_RUST) -// TODO: Correct FFMpeg integration -#include -#include -#include -#include -#include -#include "hardsubx.h" - -int64_t convert_pts_to_ms(int64_t pts, AVRational time_base) -{ - return av_rescale_q(pts, time_base, AV_TIME_BASE_Q) / 1000; -} - -int64_t convert_pts_to_ns(int64_t pts, AVRational time_base) -{ - return av_rescale_q(pts, time_base, AV_TIME_BASE_Q); -} - -int64_t convert_pts_to_s(int64_t pts, AVRational time_base) -{ - return av_rescale_q(pts, time_base, AV_TIME_BASE_Q) / 1000000; -} - -int edit_distance(char *word1, char *word2, int len1, int len2) -{ - // len2 <= len1 - if (len2 > len1) - { - int tmp = len1; - len1 = len2; - len2 = tmp; - - char *tmp_ptr = word1; - word1 = word2; - word2 = tmp_ptr; - } - - int **matrix = (int **)malloc(2 * sizeof(int *)); - for (int i = 0; i < 2; i++) - matrix[i] = (int *)malloc((len2 + 1) * sizeof(int)); - - int i, delete, insert, substitute, minimum; - for (i = 0; i <= len2; i++) - matrix[0][i] = i; - for (i = 1; i <= len1; i++) - { - int j; - for (j = 0; j <= len2; j++) - matrix[i % 2][j] = 0; - matrix[i % 2][0] = i; - - char c1; - c1 = word1[i - 1]; - for (j = 1; j <= len2; j++) - { - char c2; - c2 = word2[j - 1]; - if (c1 == c2) - { - matrix[i % 2][j] = matrix[(i - 1) % 2][j - 1]; - } - else - { - delete = matrix[(i - 1) % 2][j] + 1; - insert = matrix[i % 2][j - 1] + 1; - substitute = matrix[(i - 1) % 2][j - 1] + 1; - minimum = delete; - if (insert < minimum) - { - minimum = insert; - } - if (substitute < minimum) - { - minimum = substitute; - } - matrix[i % 2][j] = minimum; - } - } - } - - int ret = matrix[len1 % 2][len2]; - for (int i = 0; i < 2; i++) - free(matrix[i]); - free(matrix); - return ret; -} - -int is_valid_trailing_char(char c) -{ - char *prune_text = ",~`'-_+=‘:;” \n"; - printf("%c ", c); - int ret = 1; - size_t len = strlen(prune_text); - - for (int i = 0; i < len; i++) - { - if (prune_text[i] == c) - { - ret = -1; - break; - } - } - printf("%d\n", ret); - return ret; -} - -char *prune_string(char *s) -{ - size_t size; - char *end; - - size = strlen(s); - - if (!size) - return s; - - end = s + size - 1; - while (end >= s && is_valid_trailing_char(*end) == -1) - end--; - *(end + 1) = '\0'; - - while (*s && is_valid_trailing_char(*end) == -1) - s++; - printf("%s\n", s); - return s; -} - -#endif diff --git a/src/lib_ccx/lib_ccx.h b/src/lib_ccx/lib_ccx.h index a765ae8f9..531be1fe5 100644 --- a/src/lib_ccx/lib_ccx.h +++ b/src/lib_ccx/lib_ccx.h @@ -153,17 +153,13 @@ struct lib_ccx_ctx struct lib_ccx_ctx *init_libraries(struct ccx_s_options *opt); void dinit_libraries( struct lib_ccx_ctx **ctx); -#ifndef DISABLE_RUST extern void ccxr_init_basic_logger(); -#endif //ccextractor.c void print_end_msg(void); //params.c -#ifndef DISABLE_RUST extern int ccxr_parse_parameters(int argc, char *argv[]); -#endif int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[]); void print_usage (void); int atoi_hex (char *s); diff --git a/src/lib_ccx/params.c b/src/lib_ccx/params.c index d46d30cdf..38bfb4cf9 100644 --- a/src/lib_ccx/params.c +++ b/src/lib_ccx/params.c @@ -35,97 +35,10 @@ #define DEFAULT_FONT_PATH_ITALICS "/usr/share/fonts/truetype/noto/NotoSans-Italic.ttf" #endif -#ifndef DISABLE_RUST extern void ccxr_init_logger(); -#endif static int inputfile_capacity = 0; -size_t remove_trailing_whitespace(char *line) -{ - char *c = line + strlen(line) - 1; - while (c >= line && isspace(*c)) - c--; - c[1] = '\0'; - return c - line + 1; -} - -int process_word_file(const char *filename, struct word_list *list) -{ - int ret = 0; - FILE *fi; - if ((fi = fopen(filename, "r")) == NULL) - { - mprint("\rUnable to open word list file: %s\n", filename); - return -1; - } - - char line[CCX_DECODER_608_SCREEN_WIDTH + 3]; // For screen width + (CR)LF + '\0' == screewdith + 3 - int num = 0; - while (fgets(line, CCX_DECODER_608_SCREEN_WIDTH + 3, fi)) - { - num++; - if (line[0] == '#') // Treat lines starting with '#' as comments - continue; - - size_t new_len = remove_trailing_whitespace(line); - - if (new_len > CCX_DECODER_608_SCREEN_WIDTH) - { - mprint("Word in line %d too long, max = %d characters.\n", num, CCX_DECODER_608_SCREEN_WIDTH); - continue; - } - - if (new_len > 0) - { - if (add_word(list, line) == -1) - { - ret = -1; - break; - } - } - } - fclose(fi); - return ret; -} - -int isanumber(char *s) -{ - while (*s) - { - if (!isdigit(*s)) - return 0; - s++; - } - return 1; -} - -int parsedelay(struct ccx_s_options *opt, char *par) -{ - int sign = 0; - char *c = par; - while (*c) - { - if (*c == '-' || *c == '+') - { - if (c != par) // Sign only at the beginning - return 1; - if (*c == '-') - sign = 1; - } - else - { - if (!isdigit(*c)) - return 1; - opt->subs_delay = opt->subs_delay * 10 + (*c - '0'); - } - c++; - } - if (sign) - opt->subs_delay = -opt->subs_delay; - return 0; -} - void set_binary_mode() { #ifdef WIN32 @@ -133,216 +46,6 @@ void set_binary_mode() #endif } -int append_file_to_queue(struct ccx_s_options *opt, char *filename) -{ - if (filename[0] == '\0') // skip files with empty file name (ex : ./ccextractor "") - return 0; - char *c = (char *)malloc(strlen(filename) + 1); - if (c == NULL) - return -1; - strcpy(c, filename); - if (inputfile_capacity <= opt->num_input_files) - { - inputfile_capacity += 10; - opt->inputfile = (char **)realloc(opt->inputfile, sizeof(char *) * inputfile_capacity); - if (opt->inputfile == NULL) - { - free(c); - return -1; - } - } - opt->inputfile[opt->num_input_files] = c; - opt->num_input_files++; - return 0; -} - -int add_file_sequence(struct ccx_s_options *opt, char *filename) -{ - int m, n; - n = strlen(filename) - 1; - // Look for the last digit in filename - while (n >= 0 && !isdigit(filename[n])) - n--; - if (n == -1) // None. No expansion needed - return append_file_to_queue(opt, filename); - m = n; - while (m >= 0 && isdigit(filename[m])) - m--; - m++; - // Here: Significant digits go from filename[m] to filename[n] - char *num = (char *)malloc(n - m + 2); - if (!num) - return -1; - strncpy(num, filename + m, n - m + 1); - num[n - m + 1] = 0; - int i = atoi(num); - char *temp = (char *)malloc(n - m + 3); // For overflows - if (!temp) - { - free(num); - return -1; - } - // printf ("Expanding %d to %d, initial value=%d\n",m,n,i); - for (;;) - { - FILE *f = fopen(filename, "r"); - if (f == NULL) // Doesn't exist or we can't read it. We're done - break; - fclose(f); - if (append_file_to_queue(opt, filename)) // Memory panic - { - free(num); - free(temp); - return -1; - } - i++; - sprintf(temp, "%d", i); - - int temp_len = strlen(temp); - int num_len = strlen(num); - if (temp_len > num_len) // From 999 to 1000, etc. - break; - memcpy(filename + m + (num_len - temp_len), temp, temp_len); - memset(filename + m, '0', num_len - temp_len); - } - free(num); - free(temp); - return 0; -} - -void set_output_format(struct ccx_s_options *opt, const char *format) -{ - opt->write_format_rewritten = 1; - - while (*format == '-') - format++; - - if (opt->send_to_srv && strcmp(format, "bin") != 0) - { - mprint("Output format is changed to bin\n"); - format = "bin"; - } - - if (strcmp(format, "ass") == 0) - { - opt->write_format = CCX_OF_SSA; - opt->use_ass_instead_of_ssa = 1; - } - else if (strcmp(format, "ccd") == 0) - opt->write_format = CCX_OF_CCD; - else if (strcmp(format, "scc") == 0) - opt->write_format = CCX_OF_SCC; - else if (strcmp(format, "srt") == 0) - opt->write_format = CCX_OF_SRT; - else if (strcmp(format, "ssa") == 0) - opt->write_format = CCX_OF_SSA; - else if (strcmp(format, "webvtt") == 0) - opt->write_format = CCX_OF_WEBVTT; - else if (strcmp(format, "webvtt-full") == 0) - { - opt->write_format = CCX_OF_WEBVTT; - opt->use_webvtt_styling = 1; - } - else if (strcmp(format, "sami") == 0 || strcmp(format, "smi") == 0) - opt->write_format = CCX_OF_SAMI; - else if (strcmp(format, "transcript") == 0 || strcmp(format, "txt") == 0) - { - opt->write_format = CCX_OF_TRANSCRIPT; - opt->settings_dtvcc.no_rollup = 1; - } - else if (strcmp(format, "timedtranscript") == 0 || strcmp(format, "ttxt") == 0) - { - opt->write_format = CCX_OF_TRANSCRIPT; - if (opt->date_format == ODF_NONE) - opt->date_format = ODF_HHMMSSMS; - // Sets the right things so that timestamps and the mode are printed. - if (!opt->transcript_settings.isFinal) - { - opt->transcript_settings.showStartTime = 1; - opt->transcript_settings.showEndTime = 1; - opt->transcript_settings.showCC = 0; - opt->transcript_settings.showMode = 1; - } - } - else if (strcmp(format, "report") == 0) - { - opt->write_format = CCX_OF_NULL; - opt->messages_target = 0; - opt->print_file_reports = 1; - opt->demux_cfg.ts_allprogram = CCX_TRUE; - } - else if (strcmp(format, "raw") == 0) - opt->write_format = CCX_OF_RAW; - else if (strcmp(format, "smptett") == 0) - opt->write_format = CCX_OF_SMPTETT; - else if (strcmp(format, "bin") == 0) - opt->write_format = CCX_OF_RCWT; - else if (strcmp(format, "null") == 0) - opt->write_format = CCX_OF_NULL; - else if (strcmp(format, "dvdraw") == 0) - opt->write_format = CCX_OF_DVDRAW; - else if (strcmp(format, "spupng") == 0) - opt->write_format = CCX_OF_SPUPNG; - else if (strcmp(format, "simplexml") == 0) - opt->write_format = CCX_OF_SIMPLE_XML; - else if (strcmp(format, "g608") == 0) - opt->write_format = CCX_OF_G608; -#ifdef WITH_LIBCURL - else if (strcmp(format, "curl") == 0) - opt->write_format = CCX_OF_CURL; -#endif - else if (strcmp(format, "mcc") == 0) - opt->write_format = CCX_OF_MCC; - else - fatal(EXIT_MALFORMED_PARAMETER, "Unknown output file format: %s\n", format); -} - -void set_input_format(struct ccx_s_options *opt, const char *format) -{ - if (opt->input_source == CCX_DS_TCP && strcmp(format, "bin") != 0) - { - mprint("Input format is changed to bin\n"); - format = "bin"; - } - - while (*format == '-') - format++; - if (strcmp(format, "es") == 0) // Does this actually do anything? - opt->demux_cfg.auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND; - else if (strcmp(format, "ts") == 0) - { - opt->demux_cfg.auto_stream = CCX_SM_TRANSPORT; - opt->demux_cfg.m2ts = 0; - } - else if (strcmp(format, "m2ts") == 0) - { - opt->demux_cfg.auto_stream = CCX_SM_TRANSPORT; - opt->demux_cfg.m2ts = 1; - } - else if (strcmp(format, "ps") == 0 || strcmp(format, "nots") == 0) - opt->demux_cfg.auto_stream = CCX_SM_PROGRAM; - else if (strcmp(format, "asf") == 0 || strcmp(format, "dvr-ms") == 0) - opt->demux_cfg.auto_stream = CCX_SM_ASF; - else if (strcmp(format, "wtv") == 0) - opt->demux_cfg.auto_stream = CCX_SM_WTV; - else if (strcmp(format, "raw") == 0) - opt->demux_cfg.auto_stream = CCX_SM_MCPOODLESRAW; - else if (strcmp(format, "bin") == 0) - opt->demux_cfg.auto_stream = CCX_SM_RCWT; - else if (strcmp(format, "mp4") == 0) - opt->demux_cfg.auto_stream = CCX_SM_MP4; - else if (strcmp(format, "mkv") == 0) - opt->demux_cfg.auto_stream = CCX_SM_MKV; - else if (strcmp(format, "mxf") == 0) - opt->demux_cfg.auto_stream = CCX_SM_MXF; -#ifdef WTV_DEBUG - else if (strcmp(format, "hex") == 0) - opt->demux_cfg.auto_stream = CCX_SM_HEX_DUMP; -#endif - else - fatal(EXIT_MALFORMED_PARAMETER, "Unknown input file format: %s\n", format); -} - void print_usage(void) { mprint("Originally based on McPoodle's tools. Check his page for lots of information\n"); @@ -1052,11 +755,7 @@ void version(char *location) mprint(" Version: %s\n", VERSION); mprint(" Git commit: %s\n", GIT_COMMIT); mprint(" Compilation date: %s\n", COMPILE_DATE); -#ifndef DISABLE_RUST - mprint(" CEA-708 decoder: Rust\n"); -#else - mprint(" CEA-708 decoder: C\n"); -#endif + mprint(" CEA-708 decoder: \n"); mprint(" File SHA256: %s\n", hash); mprint("Libraries used by CCExtractor\n"); @@ -1076,105 +775,6 @@ void version(char *location) mprint(" libzvbi\n"); } -void parse_708_services(struct ccx_s_options *opts, char *s) -{ - const char *all = "all"; - size_t all_len = strlen(all); - int diff = strncmp(s, all, all_len); - if (diff == 0) - { - size_t s_len = strlen(s); - char *charset = NULL; - if (s_len > all_len + 2) // '[' and ']' - charset = strndup(s + all_len + 1, s_len - all_len - 2); - - opts->settings_dtvcc.enabled = 1; - opts->enc_cfg.dtvcc_extract = 1; - opts->enc_cfg.all_services_charset = charset; - - opts->enc_cfg.services_charsets = (char **)calloc(sizeof(char *), CCX_DTVCC_MAX_SERVICES); - if (!opts->enc_cfg.services_charsets) - ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "parse_708_services"); - memset(opts->enc_cfg.services_charsets, 0, CCX_DTVCC_MAX_SERVICES * sizeof(char *)); - - for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++) - { - opts->settings_dtvcc.services_enabled[i] = 1; - opts->enc_cfg.services_enabled[i] = 1; - } - - opts->settings_dtvcc.active_services_count = CCX_DTVCC_MAX_SERVICES; - return; - } - - char *c, *e, *l; - if (s == NULL) - return; - l = s + strlen(s); - for (c = s; c < l && *c;) - { - int svc = -1; - while (*c && !isdigit(*c)) - c++; - if (!*c) // We're done - break; - e = c; - while (isdigit(*e)) - e++; - int charset_start_found = (*e == '['); - *e = 0; - svc = atoi(c); - if (svc < 1 || svc > CCX_DTVCC_MAX_SERVICES) - fatal(EXIT_MALFORMED_PARAMETER, - "[CEA-708] Malformed parameter: Invalid service number (%d), valid range is 1-%d.\n", svc, CCX_DTVCC_MAX_SERVICES); - opts->settings_dtvcc.services_enabled[svc - 1] = 1; - opts->enc_cfg.services_enabled[svc - 1] = 1; - opts->settings_dtvcc.enabled = 1; - opts->enc_cfg.dtvcc_extract = 1; - opts->settings_dtvcc.active_services_count++; - - if (!opts->enc_cfg.services_charsets) - { - opts->enc_cfg.services_charsets = (char **)calloc(sizeof(char *), CCX_DTVCC_MAX_SERVICES); - if (!opts->enc_cfg.services_charsets) - ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "parse_708_services\n"); - memset(opts->enc_cfg.services_charsets, 0, CCX_DTVCC_MAX_SERVICES * sizeof(char *)); - } - - e = e + 1; - c = e; - - if (!charset_start_found) - continue; - - while (*e && *e != ']' && *e != ',') - e++; - if (*e == ']') - { - char *charset = strndup(c, e - c); - if (strlen(charset)) - opts->enc_cfg.services_charsets[svc - 1] = charset; - c = e + 1; - } - else if (!*e) - { - fatal(EXIT_MALFORMED_PARAMETER, "[CEA-708] Malformed parameter: missing closing ] in CEA-708 services list\n"); - } - } - if (opts->settings_dtvcc.active_services_count <= 0) - fatal(EXIT_MALFORMED_PARAMETER, "[CEA-708] Malformed parameter: no services\n"); -} - -long atol_size(char *s) -{ - long val = atoi(s); - if (toupper(s[strlen(s) - 1]) == 'M') - val *= 1024 * 1024; - else if (toupper(s[strlen(s) - 1]) == 'K') - val *= 1024; - return val; -} - int atoi_hex(char *s) { if (strlen(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) @@ -1187,1810 +787,3 @@ int atoi_hex(char *s) return atoi(s); } } - -void mkvlang_params_check(char *lang) -{ - int initial = 0, present = 0; - for (int char_index = 0; char_index < strlen(lang); char_index++) - { - lang[char_index] = cctolower(lang[char_index]); - if (lang[char_index] == ',') - { - present = char_index; - if ((present - initial < 6) && (present - initial != 3)) - fatal(EXIT_MALFORMED_PARAMETER, "language codes should be xxx,xxx,xxx,....\n"); - - else if ((present - initial > 3) && (present - initial != 6)) - fatal(EXIT_MALFORMED_PARAMETER, "language codes should be xxx-xx,xxx-xx,xxx-xx,....\n"); - - if ((present - initial > 3) && (present - initial == 6)) - { - size_t length = present - initial; - char *block = calloc(length + 1, sizeof(char)); - strncpy(block, lang + initial, length); - char *hiphen_pointer = strstr(block, "-"); - if (!hiphen_pointer) - fatal(EXIT_MALFORMED_PARAMETER, "language code is not of the form xxx-xx\n"); - free(block); - } - initial = present + 1; - } - } - - // Steps to check for the last lang of multiple mkvlangs provided by the user. - present = strlen(lang) - 1; - - for (int char_index = strlen(lang) - 1; char_index >= 0; char_index--) - if (lang[char_index] == ',') - { - initial = char_index + 1; - break; - } - - if ((present - initial < 5) && (present - initial != 2)) - fatal(EXIT_MALFORMED_PARAMETER, "last language code should be xxx.\n"); - - else if ((present - initial > 2) && (present - initial != 5)) - fatal(EXIT_MALFORMED_PARAMETER, "last language code should be xxx-xx.\n"); - - if ((present - initial > 2) && (present - initial == 5)) - { - size_t length = present - initial; - char *block = calloc(length + 1, sizeof(char)); - strncpy(block, lang + initial, length); - char *hiphen_pointer = strstr(block, "-"); - if (!hiphen_pointer) - fatal(EXIT_MALFORMED_PARAMETER, "last language code is not of the form xxx-xx\n"); - free(block); - } -} - -int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) -{ - for (int i = 1; i < argc; i++) - { - if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) - { - print_usage(); - return EXIT_WITH_HELP; - } - if (strcmp(argv[i], "--version") == 0) - { - version(argv[0]); - return EXIT_WITH_HELP; - } - if (strcmp(argv[i], "-") == 0 || strcmp(argv[i], "--stdin") == 0) - { - set_binary_mode(); - - opt->input_source = CCX_DS_STDIN; - if (!opt->live_stream) - opt->live_stream = -1; - continue; - } - if (argv[i][0] != '-') - { - int rc; - if (argv[i][strlen(argv[i]) - 1] != '+') - { - rc = append_file_to_queue(opt, argv[i]); - } - else - { - argv[i][strlen(argv[i]) - 1] = 0; - rc = add_file_sequence(opt, argv[i]); - } - if (rc) - { - fatal(EXIT_NOT_ENOUGH_MEMORY, "Fatal: Not enough memory to parse parameters.\n"); - } - continue; - } - -#ifdef ENABLE_HARDSUBX - // Parse --hardsubx and related parameters - if (strcmp(argv[i], "--hardsubx") == 0) - { - opt->hardsubx = 1; - continue; - } - if (opt->hardsubx == 1) - { - if (strcmp(argv[i], "--hcc") == 0) - { - // if extraction of both burned in and non burned in subs - opt->hardsubx_and_common = 1; - continue; - } - if (strcmp(argv[i], "--ocr-mode") == 0) - { - if (i < argc - 1) - { - i++; - - if (strcmp(argv[i], "simple") == 0 || strcmp(argv[i], "frame") == 0) - { - opt->hardsubx_ocr_mode = HARDSUBX_OCRMODE_FRAME; - } - else if (strcmp(argv[i], "word") == 0) - { - opt->hardsubx_ocr_mode = HARDSUBX_OCRMODE_WORD; - } - else if (strcmp(argv[i], "letter") == 0 || strcmp(argv[i], "symbol") == 0) - { - opt->hardsubx_ocr_mode = HARDSUBX_OCRMODE_LETTER; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "-ocr_mode has an invalid value.\nValid values are {frame,word,letter}\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "-ocr_mode has no argument.\nValid values are {frame,word,letter}\n"); - } - } - if (strcmp(argv[i], "--subcolor") == 0) - { - if (i < argc - 1) - { - i++; - - if (strcmp(argv[i], "white") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_WHITE; - opt->hardsubx_hue = 0.0; - } - else if (strcmp(argv[i], "yellow") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_YELLOW; - opt->hardsubx_hue = 60.0; - } - else if (strcmp(argv[i], "green") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_GREEN; - opt->hardsubx_hue = 120.0; - } - else if (strcmp(argv[i], "cyan") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_CYAN; - opt->hardsubx_hue = 180.0; - } - else if (strcmp(argv[i], "blue") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_BLUE; - opt->hardsubx_hue = 240.0; - } - else if (strcmp(argv[i], "magenta") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_MAGENTA; - opt->hardsubx_hue = 300.0; - } - else if (strcmp(argv[i], "red") == 0) - { - opt->hardsubx_subcolor = HARDSUBX_COLOR_RED; - opt->hardsubx_hue = 0.0; - } - else - { - // Take a custom hue from the user - opt->hardsubx_subcolor = HARDSUBX_COLOR_CUSTOM; - char *str = (char *)malloc(sizeof(argv[i])); - sprintf(str, "%s", argv[i]); // Done this way to avoid error with getting (i+1)th env variable - opt->hardsubx_hue = atof(str); - if (opt->hardsubx_hue <= 0.0 || opt->hardsubx_hue > 360.0) - { - fatal(EXIT_MALFORMED_PARAMETER, "--subcolor has either 0 or an invalid hue value supplied.\nIf you want to detect red subtitles, pass '-subcolor red' or a slightly higher hue value (e.g. 0.1)\n"); - } - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--subcolor has no argument.\nValid values are {white,yellow,green,cyan,blue,magenta,red} or a custom hue value between 0 and 360\n"); - } - } - if (strcmp(argv[i], "--min-sub-duration") == 0) - { - if (i < argc - 1) - { - i++; - - char *str = (char *)malloc(sizeof(argv[i])); - sprintf(str, "%s", argv[i]); // Done this way to avoid error with getting (i+1)th env variable - opt->hardsubx_min_sub_duration = atof(str); - if (opt->hardsubx_min_sub_duration == 0.0) - { - fatal(EXIT_MALFORMED_PARAMETER, "--min-sub-duration has either 0 or an invalid value supplied\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--min-sub-duration has no argument.\n"); - } - } - if (strcmp(argv[i], "--detect-italics") == 0) - { - opt->hardsubx_detect_italics = 1; - continue; - } - if (strcmp(argv[i], "--conf-thresh") == 0) - { - if (i < argc - 1) - { - i++; - - char *str = (char *)malloc(sizeof(argv[i])); - sprintf(str, "%s", argv[i]); // Done this way to avoid error with getting (i+1)th env variable - opt->hardsubx_conf_thresh = atof(str); - if (opt->hardsubx_conf_thresh <= 0.0 || opt->hardsubx_conf_thresh > 100.0) - { - fatal(EXIT_MALFORMED_PARAMETER, "--conf-thresh has either 0 or an invalid value supplied\nValid values are in (0.0,100.0)\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--conf-thresh has no argument.\n"); - } - } - if (strcmp(argv[i], "--whiteness-thresh") == 0 || strcmp(argv[i], "--lum-thresh") == 0) - { - if (i < argc - 1) - { - i++; - - char *str = (char *)malloc(sizeof(argv[i])); - sprintf(str, "%s", argv[i]); // Done this way to avoid error with getting (i+1)th env variable - opt->hardsubx_lum_thresh = atof(str); - if (opt->hardsubx_lum_thresh <= 0.0 || opt->hardsubx_conf_thresh > 100.0) - { - fatal(EXIT_MALFORMED_PARAMETER, "--whiteness-thresh has either 0 or an invalid value supplied\nValid values are in (0.0,100.0)\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--whiteness-thresh has no argument.\n"); - } - } - } -#endif // ENABLE_HARDSUBX - - if (strcmp(argv[i], "--chapters") == 0) - { - opt->extract_chapters = 1; - continue; - } - if (strcmp(argv[i], "--bufferinput") == 0) - { - opt->buffer_input = 1; - continue; - } - if (strcmp(argv[i], "--no-bufferinput") == 0) - { - opt->buffer_input = 0; - continue; - } - if (strcmp(argv[i], "--koc") == 0) - { - opt->keep_output_closed = 1; - continue; - } - if (strcmp(argv[i], "--forceflush") == 0) - { - opt->force_flush = 1; - continue; - } - if (strcmp(argv[i], "--append") == 0) - { - opt->append_mode = 1; - continue; - } - if (strcmp(argv[i], "--buffersize") == 0) - { - if (i < argc - 1) - { - i++; - - FILEBUFFERSIZE = atol_size(argv[i]); - if (FILEBUFFERSIZE < 8) - { - FILEBUFFERSIZE = 8; // Otherwise crashes are guaranteed at least in MythTV - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--buffersize has no argument.\n"); - } - } - if (strcmp(argv[i], "--dru") == 0) - { - opt->settings_608.direct_rollup = 1; - continue; - } - if (strcmp(argv[i], "--no-fontcolor") == 0) - { - opt->nofontcolor = 1; - continue; - } - if (strcmp(argv[i], "--no-htmlescape") == 0) - { - opt->nohtmlescape = 1; - continue; - } - if (strcmp(argv[i], "--bom") == 0) - { - opt->enc_cfg.no_bom = 0; - continue; - } - if (strcmp(argv[i], "--no-bom") == 0) - { - opt->enc_cfg.no_bom = 1; - continue; - } - if (strcmp(argv[i], "--sem") == 0) - { - opt->enc_cfg.with_semaphore = 1; - continue; - } - if (strcmp(argv[i], "--no-typesetting") == 0) - { - opt->notypesetting = 1; - continue; - } - - if (strcmp(argv[i], "--timestamp-map") == 0) - { - opt->timestamp_map = 1; - continue; - } - - /* Input file formats */ - if (strcmp(argv[i], "--es") == 0 || - strcmp(argv[i], "--ts") == 0 || - strcmp(argv[i], "--ps") == 0 || - strcmp(argv[i], "--asf") == 0 || - strcmp(argv[i], "--wtv") == 0 || - strcmp(argv[i], "--mp4") == 0 || - strcmp(argv[i], "--mkv") == 0 || - strcmp(argv[i], "--dvr-ms") == 0) - { - set_input_format(opt, argv[i]); - continue; - } - if (strncmp(argv[i], "--in=", 5) == 0) - { - set_input_format(opt, argv[i] + 5); - continue; - } - - /*user specified subtitle to be selected */ - if (strcmp(argv[i], "--codec") == 0) - { - if (i < argc - 1) - { - i++; - - if (strcmp(argv[i], "teletext") == 0) - { - opt->demux_cfg.codec = CCX_CODEC_TELETEXT; - } - else if (strcmp(argv[i], "dvbsub") == 0) - { - opt->demux_cfg.codec = CCX_CODEC_DVB; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "Invalid option for codec.\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--codec has no argument.\n"); - } - } - - /*user specified subtitle to be selected */ - if (strcmp(argv[i], "--no-codec") == 0) - { - if (i < argc - 1) - { - i++; - - if (strcmp(argv[i], "teletext") == 0) - { - opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT; - } - else if (strcmp(argv[i], "dvbsub") == 0) - { - opt->demux_cfg.nocodec = CCX_CODEC_DVB; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "Invalid option for no-codec.\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--no-codec has no argument.\n"); - } - } - - if (strcmp(argv[i], "--dvblang") == 0) - { - if (i < argc - 1) - { - i++; - - opt->dvblang = (char *)malloc(sizeof(argv[i])); - sprintf(opt->dvblang, "%s", argv[i]); - for (int char_index = 0; char_index < strlen(opt->dvblang); char_index++) - { - opt->dvblang[char_index] = cctolower(opt->dvblang[char_index]); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--dvblang has no argument.\n"); - } - } - - if (strcmp(argv[i], "--ocrlang") == 0) - { - if (i++ < argc - 1) - { - opt->ocrlang = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--ocrlang has no argument.\n"); - } - } - if (strcmp(argv[i], "--quant") == 0) - { - if (i < argc - 1) - { - i++; - opt->ocr_quantmode = atoi(argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--quant has no argument.\n"); - } - } - if (strcmp(argv[i], "--no-spupngocr") == 0) - { - opt->enc_cfg.nospupngocr = 1; - continue; - } - if (strcmp(argv[i], "--oem") == 0) - { - if (i < argc - 1) - { - i++; - - char *str = (char *)malloc(sizeof(argv[i])); - sprintf(str, "%s", argv[i]); - opt->ocr_oem = atoi(str); - if (opt->ocr_oem < 0 || opt->ocr_oem > 2) - { - fatal(EXIT_MALFORMED_PARAMETER, "--oem must be 0, 1 or 2\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--oem has no argument.\n"); - } - } - if (strcmp(argv[i], "--psm") == 0) - { - if (i < argc - 1) - { - i++; - - char *str = (char *)malloc(sizeof(argv[i])); - sprintf(str, "%s", argv[i]); - opt->psm = atoi(str); - if (opt->psm < 0 || opt->psm > 13) - { - fatal(EXIT_MALFORMED_PARAMETER, "--psm must be between 0 and 13\n"); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--psm has no argument.\n"); - } - } - if (strcmp(argv[i], "--mkvlang") == 0) - { - if (i < argc - 1) - { - i++; - - opt->mkvlang = (char *)malloc(sizeof(argv[i])); - sprintf(opt->mkvlang, "%s", argv[i]); - mkvlang_params_check(opt->mkvlang); - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--mkvlang has no argument.\n"); - } - } - - /* Output file formats */ - if (strcmp(argv[i], "--srt") == 0 || - strcmp(argv[i], "--mcc") == 0 || strcmp(argv[i], "--dvdraw") == 0 || - strcmp(argv[i], "--smi") == 0 || strcmp(argv[i], "--sami") == 0 || - strcmp(argv[i], "--txt") == 0 || strcmp(argv[i], "--transcript") == 0 || - strcmp(argv[i], "--ttxt") == 0 || strcmp(argv[i], "--timedtranscript") == 0 || - strcmp(argv[i], "--webvtt") == 0 || strcmp(argv[i], "--null") == 0) - { - set_output_format(opt, argv[i]); - continue; - } - if (strncmp(argv[i], "--out=", 6) == 0) - { - set_output_format(opt, argv[i] + 6); - continue; - } - - /* Credit stuff */ - if (strcmp(argv[i], "--startcreditstext") == 0) - { - if (i < argc - 1) - { - i++; - opt->enc_cfg.start_credits_text = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditstext has no argument.\n"); - } - } - if (strcmp(argv[i], "--startcreditsnotbefore") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->enc_cfg.startcreditsnotbefore) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsnotbefore only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsnotbefore has no argument.\n"); - } - } - if (strcmp(argv[i], "--startcreditsnotafter") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->enc_cfg.startcreditsnotafter) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsnotafter only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsnotafter has no argument.\n"); - } - } - if (strcmp(argv[i], "--startcreditsforatleast") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->enc_cfg.startcreditsforatleast) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsforatleast only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsforatleast has no argument.\n"); - } - } - if (strcmp(argv[i], "--startcreditsforatmost") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->enc_cfg.startcreditsforatmost) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost has no argument.\n"); - } - } - if (strcmp(argv[i], "--endcreditstext") == 0) - { - if (i < argc - 1) - { - i++; - opt->enc_cfg.end_credits_text = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--endcreditstext has no argument.\n"); - } - } - if (strcmp(argv[i], "--endcreditsforatleast") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->enc_cfg.endcreditsforatleast) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--endcreditsforatleast only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--endcreditsforatleast has no argument.\n"); - } - } - if (strcmp(argv[i], "--endcreditsforatmost") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->enc_cfg.endcreditsforatmost) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--startcreditsforatmost only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--endcreditsforatmost has no argument.\n"); - } - } - - /* More stuff */ - if (strcmp(argv[i], "--videoedited") == 0) - { - opt->binary_concat = 0; - continue; - } - if (strcmp(argv[i], "--goptime") == 0) - { - opt->use_gop_as_pts = 1; - continue; - } - if (strcmp(argv[i], "--no-goptime") == 0) - { - opt->use_gop_as_pts = -1; // Don't use even if we would want to - continue; - } - if (strcmp(argv[i], "--fixpadding") == 0) - { - opt->fix_padding = 1; - continue; - } - if (strcmp(argv[i], "--90090") == 0) - { - MPEG_CLOCK_FREQ = 90090; - continue; - } - if (strcmp(argv[i], "--no-scte20") == 0) - { - opt->noscte20 = 1; - continue; - } - if (strcmp(argv[i], "--webvtt-create-css") == 0) - { - opt->webvtt_create_css = 1; - continue; - } - if (strcmp(argv[i], "--no-rollup") == 0) - { - opt->no_rollup = 1; - opt->settings_608.no_rollup = 1; - opt->settings_dtvcc.no_rollup = 1; - continue; - } - if (strcmp(argv[i], "--ru1") == 0) - { - opt->settings_608.force_rollup = 1; - continue; - } - if (strcmp(argv[i], "--ru2") == 0) - { - opt->settings_608.force_rollup = 2; - continue; - } - if (strcmp(argv[i], "--ru3") == 0) - { - opt->settings_608.force_rollup = 3; - continue; - } - if (strcmp(argv[i], "--trim") == 0) - { - opt->enc_cfg.trim_subs = 1; - continue; - } - if (strcmp(argv[i], "--outinterval") == 0) - { - if (i < argc - 1) - { - i++; - opt->out_interval = atoi(argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "-outinterval has no argument.\n"); - } - } - if (strcmp(argv[i], "--segmentonkeyonly") == 0) - { - opt->segment_on_key_frames_only = 1; - opt->analyze_video_stream = 1; - continue; - } - if (strcmp(argv[i], "--gui-mode-reports") == 0) - { - opt->gui_mode_reports = 1; - continue; - } - if (strcmp(argv[i], "--no-progress-bar") == 0) - { - opt->no_progress_bar = 1; - continue; - } - if (strcmp(argv[i], "--splitbysentence") == 0) - { - opt->enc_cfg.splitbysentence = 1; - continue; - } - - if (strcmp(argv[i], "--sentencecap") == 0) - { - opt->enc_cfg.sentence_cap = 1; - continue; - } - - if (strcmp(argv[i], "--capfile") == 0 && i < argc - 1) - { - opt->enc_cfg.sentence_cap = 1; - opt->sentence_cap_file = argv[i + 1]; - i++; - continue; - } - - if (strcmp(argv[i], "--kf") == 0) // Kid friendly (removes profanity) - { - opt->enc_cfg.filter_profanity = 1; - continue; - } - - if (strcmp(argv[i], "--profanity-file") == 0) - { - // TODO: decide whether this is really wanted. A script running ccextractor - // could want to pass this argument at all time and only use it with --kf - // Issue also applies to --capfile - opt->enc_cfg.filter_profanity = 1; - opt->filter_profanity_file = argv[++i]; - continue; - } - - if (strcmp(argv[i], "--program-number") == 0) - { - if (i < argc - 1 && isanumber(argv[i + 1])) - { - i++; - opt->demux_cfg.ts_forced_program = atoi_hex(argv[i]); - opt->demux_cfg.ts_forced_program_selected = 1; - continue; - } - else - { - opt->demux_cfg.ts_forced_program = -1; // Autodetect - continue; - } - } - if (strcmp(argv[i], "--autoprogram") == 0) - { - opt->demux_cfg.ts_autoprogram = 1; - continue; - } - if (strcmp(argv[i], "--multiprogram") == 0) - { - opt->multiprogram = 1; - opt->demux_cfg.ts_allprogram = CCX_TRUE; - continue; - } - if (strcmp(argv[i], "--stream") == 0 || strcmp(argv[i], "-s") == 0) - { - if (i < argc - 1 && isanumber(argv[i + 1])) - { - i++; - opt->live_stream = atoi_hex(argv[i]); - continue; - } - else - { - opt->live_stream = -1; // Live stream without timeout - continue; - } - } - if (strcmp(argv[i], "--defaultcolor") == 0) - { - if (i < argc - 1) - { - i++; - if (strlen(argv[i]) != 7 || argv[i][0] != '#') - { - fatal(EXIT_MALFORMED_PARAMETER, "--defaultcolor expects a 7 character parameter that starts with #\n"); - } - strcpy((char *)usercolor_rgb, argv[i]); - opt->settings_608.default_color = COL_USERDEFINED; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--defaultcolor has no argument.\n"); - } - } - if (strcmp(argv[i], "--delay") == 0) - { - if (i < argc - 1) - { - i++; - if (parsedelay(opt, argv[i])) - { - fatal(EXIT_MALFORMED_PARAMETER, "--delay only accept integers (such as --300 or 300)\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--delay has no argument.\n"); - } - } - if (strcmp(argv[i], "--screenfuls") == 0) - { - if (i < argc - 1) - { - i++; - opt->settings_608.screens_to_process = atoi_hex(argv[i]); - if (opt->settings_608.screens_to_process < 0) - { - fatal(EXIT_MALFORMED_PARAMETER, "--screenfuls only accepts non-negative integers.\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--screenfuls has no argument.\n"); - } - } - if (strcmp(argv[i], "--startat") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->extraction_start) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--startat only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--startat has no argument.\n"); - } - } - if (strcmp(argv[i], "--endat") == 0) - { - if (i < argc - 1) - { - i++; - if (stringztoms(argv[i], &opt->extraction_end) == -1) - { - fatal(EXIT_MALFORMED_PARAMETER, "--endat only accepts SS, MM:SS or HH:MM:SS\n"); - } - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--endat has no argument.\n"); - } - } - if (strcmp(argv[i], "--output-field") == 0) - { - if (i < argc - 1) - { - i++; - opt->extract = strcmp(argv[i], "both") == 0 ? 12 : atoi_hex(argv[i]); - if (opt->extract != 1 && opt->extract != 2 && opt->extract != 12) - { - fatal(EXIT_MALFORMED_PARAMETER, "--output-field only accepts 1 , 2 , 12 / both.\n"); - } - opt->is_608_enabled = 1; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--output-field has no argument.\n"); - } - } - - if (strcmp(argv[i], "--cc2") == 0 || strcmp(argv[i], "--CC2") == 0) - { - opt->cc_channel = 2; - continue; - } - if (strcmp(argv[i], "--stdout") == 0) - { - if (opt->messages_target == 1) // Only change this if still stdout. --quiet could set it to 0 for example - { - opt->messages_target = 2; // stderr - } - opt->cc_to_stdout = 1; - continue; - } - if (strcmp(argv[i], "--pesheader") == 0) - { - opt->pes_header_to_stdout = 1; - continue; - } - if (strcmp(argv[i], "--debugdvbsub") == 0) - { - opt->debug_mask |= CCX_DMT_DVB; - continue; - } - if (strcmp(argv[i], "--ignoreptsjumps") == 0) - { - opt->ignore_pts_jumps = 1; - continue; - } - // --ignoreptsjumps counterpart - if (strcmp(argv[i], "--fixptsjumps") == 0) - { - opt->ignore_pts_jumps = 0; - continue; - } - if (strcmp(argv[i], "--quiet") == 0) - { - opt->messages_target = 0; - continue; - } - if (strcmp(argv[i], "--debug") == 0) - { - opt->debug_mask |= CCX_DMT_VERBOSE; - continue; - } - if (strcmp(argv[i], "--608") == 0) - { - opt->debug_mask |= CCX_DMT_DECODER_608; - continue; - } - if (strcmp(argv[i], "--deblev") == 0) - { - opt->debug_mask |= CCX_DMT_LEVENSHTEIN; - continue; - } - if (strcmp(argv[i], "--no-levdist") == 0) - { - opt->dolevdist = 0; - continue; - } - if (strcmp(argv[i], "--levdistmincnt") == 0) - { - if (i < argc - 1) - { - i++; - opt->levdistmincnt = atoi_hex(argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--levdistmincnt has no argument.\n"); - } - } - if (strcmp(argv[i], "--levdistmaxpct") == 0) - { - if (i < argc - 1) - { - i++; - opt->levdistmaxpct = atoi_hex(argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--levdistmaxpct has no argument.\n"); - } - } - if (strcmp(argv[i], "--708") == 0) - { - opt->debug_mask |= CCX_DMT_708; -#ifndef DISABLE_RUST - ccxr_init_logger(); -#endif - continue; - } - if (strcmp(argv[i], "--goppts") == 0) - { - opt->debug_mask |= CCX_DMT_TIME; - continue; - } - if (strcmp(argv[i], "--vides") == 0) - { - opt->debug_mask |= CCX_DMT_VIDES; - opt->analyze_video_stream = 1; - continue; - } - if (strcmp(argv[i], "--analyzevideo") == 0) - { - opt->analyze_video_stream = 1; - continue; - } - if (strcmp(argv[i], "--xds") == 0) - { - // XDS can be set regardless of --UCLA (isFinal) usage. - opt->transcript_settings.xds = 1; - continue; - } - if (strcmp(argv[i], "--xdsdebug") == 0) - { - opt->transcript_settings.xds = 1; - opt->debug_mask |= CCX_DMT_DECODER_XDS; - continue; - } - if (strcmp(argv[i], "--parsedebug") == 0) - { - opt->debug_mask |= CCX_DMT_PARSE; - continue; - } - if (strcmp(argv[i], "--parsePAT") == 0 || strcmp(argv[i], "--parsepat") == 0) - { - opt->debug_mask |= CCX_DMT_PAT; - continue; - } - if (strcmp(argv[i], "--parsePMT") == 0 || strcmp(argv[i], "--parsepmt") == 0) - { - opt->debug_mask |= CCX_DMT_PMT; - continue; - } - if (strcmp(argv[i], "--dumpdef") == 0) - { - opt->debug_mask |= CCX_DMT_DUMPDEF; - continue; - } - if (strcmp(argv[i], "--investigate-packets") == 0) - { - opt->investigate_packets = 1; - continue; - } - if (strcmp(argv[i], "--cbraw") == 0) - { - opt->debug_mask |= CCX_DMT_CBRAW; - continue; - } - if (strcmp(argv[i], "--tverbose") == 0) - { - opt->debug_mask |= CCX_DMT_TELETEXT; - tlt_config.verbose = 1; - continue; - } - if (strcmp(argv[i], "--fullbin") == 0) - { - opt->fullbin = 1; - continue; - } - if (strcmp(argv[i], "--no-sync") == 0) - { - opt->nosync = 1; - continue; - } - if (strcmp(argv[i], "--hauppauge") == 0) - { - opt->hauppauge_mode = 1; - continue; - } - if (strcmp(argv[i], "--mp4vidtrack") == 0) - { - opt->mp4vidtrack = 1; - continue; - } - if (strstr(argv[i], "--unicode") != NULL) - { - opt->enc_cfg.encoding = CCX_ENC_UNICODE; - continue; - } - if (strstr(argv[i], "--utf8") != NULL) - { - opt->enc_cfg.encoding = CCX_ENC_UTF_8; - continue; - } - if (strstr(argv[i], "--latin1") != NULL) - { - opt->enc_cfg.encoding = CCX_ENC_LATIN_1; - continue; - } - if (strcmp(argv[i], "--usepicorder") == 0) - { - opt->usepicorder = 1; - continue; - } - if (strstr(argv[i], "--myth") != NULL) - { - opt->auto_myth = 1; - continue; - } - if (strstr(argv[i], "--no-myth") != NULL) - { - opt->auto_myth = 0; - continue; - } - if (strstr(argv[i], "--wtvconvertfix") != NULL) - { - opt->wtvconvertfix = 1; - continue; - } - if (strstr(argv[i], "--wtvmpeg2") != NULL) - { - opt->wtvmpeg2 = 1; - continue; - } - if (strcmp(argv[i], "-o") == 0) - { - if (i < argc - 1) - { - i++; - opt->output_filename = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "-o has no argument.\n"); - } - } - if (strcmp(argv[i], "--service") == 0) - { - if (i < argc - 1) - { - opt->is_708_enabled = 1; - i++; - parse_708_services(opt, argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--service has no argument.\n"); - } - } - if (strcmp(argv[i], "--datapid") == 0) - { - if (i < argc - 1) - { - i++; - opt->demux_cfg.ts_cappids[opt->demux_cfg.nb_ts_cappid] = atoi_hex(argv[i]); - opt->demux_cfg.nb_ts_cappid++; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--datapid has no argument.\n"); - } - } - if (strcmp(argv[i], "--datastreamtype") == 0) - { - if (i < argc - 1) - { - i++; - opt->demux_cfg.ts_datastreamtype = atoi_hex(argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--datastreamtype has no argument.\n"); - } - } - if (strcmp(argv[i], "--streamtype") == 0) - { - if (i < argc - 1) - { - i++; - opt->demux_cfg.ts_forced_streamtype = atoi_hex(argv[i]); - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--streamtype has no argument.\n"); - } - } - - /* Teletext stuff */ - if (strcmp(argv[i], "--tpage") == 0) - { - if (i < argc - 1) - { - i++; - tlt_config.page = atoi_hex(argv[i]); - tlt_config.user_page = tlt_config.page; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--tpage has no argument.\n"); - } - } - - /* Red Hen/ UCLA Specific stuff */ - if (strcmp(argv[i], "--UCLA") == 0 || strcmp(argv[i], "--ucla") == 0) - { - opt->ucla = 1; - opt->millis_separator = '.'; - opt->enc_cfg.no_bom = 1; - if (!opt->transcript_settings.isFinal) - { - opt->transcript_settings.showStartTime = 1; - opt->transcript_settings.showEndTime = 1; - opt->transcript_settings.showCC = 1; - opt->transcript_settings.showMode = 1; - opt->transcript_settings.relativeTimestamp = 0; - opt->transcript_settings.isFinal = 1; - } - continue; - } - if (strcmp(argv[i], "--latrusmap") == 0) - { - tlt_config.latrusmap = 1; - continue; - } - if (strcmp(argv[i], "--tickertext") == 0 || strcmp(argv[i], "--tickertape") == 0) - { - opt->tickertext = 1; - continue; - } - if (strcmp(argv[i], "--lf") == 0 || strcmp(argv[i], "--LF") == 0) - { - opt->enc_cfg.line_terminator_lf = 1; - continue; - } - if (strcmp(argv[i], "--df") == 0 || strcmp(argv[i], "--DF") == 0) - { - opt->enc_cfg.force_dropframe = 1; - continue; - } - if (strcmp(argv[i], "--no-autotimeref") == 0) - { - opt->noautotimeref = 1; - continue; - } - if (strcmp(argv[i], "--autodash") == 0 || strcmp(argv[i], "--sem") == 0) - { - opt->enc_cfg.autodash = 1; - continue; - } - if (strcmp(argv[i], "--xmltv") == 0) - { - if (i < argc - 1 && isanumber(argv[i + 1])) - { - i++; - opt->xmltv = atoi_hex(argv[i]); - continue; - } - else - { - opt->xmltv = 1; - continue; - } - } - if (strcmp(argv[i], "--xmltvliveinterval") == 0) - { - if (i < argc - 1 && isanumber(argv[i + 1])) - { - i++; - opt->xmltvliveinterval = atoi_hex(argv[i]); - continue; - } - else - { - opt->xmltvliveinterval = 10; - continue; - } - } - if (strcmp(argv[i], "--xmltvoutputinterval") == 0) - { - if (i < argc - 1 && isanumber(argv[i + 1])) - { - i++; - opt->xmltvoutputinterval = atoi_hex(argv[i]); - continue; - } - else - { - opt->xmltvoutputinterval = 0; - continue; - } - } - if (strcmp(argv[i], "--xmltvonlycurrent") == 0) - { - opt->xmltvonlycurrent = 1; - i++; // why do we skip next? - continue; - } - if (strcmp(argv[i], "--unixts") == 0) - { - if (i < argc - 1) - { - i++; - - uint64_t t = atoi_hex(argv[i]); - if (t <= 0) - { - time_t now = time(NULL); - t = time(&now); - } - utc_refvalue = t; - opt->noautotimeref = 1; // If set by user don't attempt to fix - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--unixts has no argument.\n"); - } - } - if (strcmp(argv[i], "--sects") == 0) - { - opt->date_format = ODF_SECONDS; - continue; - } - if (strcmp(argv[i], "--datets") == 0) - { - opt->date_format = ODF_DATE; - continue; - } - if (strcmp(argv[i], "--teletext") == 0) - { - opt->demux_cfg.codec = CCX_CODEC_TELETEXT; - continue; - } - if (strcmp(argv[i], "--no-teletext") == 0) - { - opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT; - continue; - } - /* Custom transcript */ - if (strcmp(argv[i], "--customtxt") == 0) - { - if (i < argc - 1) - { - i++; - - char *format = argv[i]; - if (strlen(format) == 7) - { - if (opt->date_format == ODF_NONE) - { - opt->date_format = ODF_HHMMSSMS; // Necessary for displaying times, if any would be used. - } - if (!opt->transcript_settings.isFinal) - { - opt->transcript_settings.showStartTime = format[0] - '0'; - opt->transcript_settings.showEndTime = format[1] - '0'; - opt->transcript_settings.showMode = format[2] - '0'; - opt->transcript_settings.showCC = format[3] - '0'; - opt->transcript_settings.relativeTimestamp = format[4] - '0'; - opt->transcript_settings.xds = format[5] - '0'; - opt->transcript_settings.useColors = format[6] - '0'; - } - else - { - fatal(EXIT_INCOMPATIBLE_PARAMETERS, "customtxt cannot be set after --UCLA is used!\n"); - } - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "Custom TXT format not OK: %s, expected 7 bits string\n", format); - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--customtxt has no argument.\n"); - } - } - - /* Network stuff */ - if (strcmp(argv[i], "--udp") == 0) - { - if (i < argc - 1) - { - i++; - - char *at = strchr(argv[i], '@'); - char *colon = strchr(argv[i], ':'); - if (at && !colon) - { - fatal(EXIT_MALFORMED_PARAMETER, "If --udp contains an '@', it must also contain a ':'\n"); - } - else if (at && colon) - { - *at = '\0'; - *colon = '\0'; - opt->udpsrc = argv[i]; - opt->udpaddr = at + 1; - opt->udpport = atoi_hex(colon + 1); - } - else if (colon) - { - *colon = '\0'; - opt->udpaddr = argv[i]; - opt->udpport = atoi_hex(colon + 1); - } - else - { - opt->udpaddr = NULL; - opt->udpport = atoi_hex(argv[i]); - } - opt->input_source = CCX_DS_NETWORK; - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--udp has no argument.\n"); - } - } - if (strcmp(argv[i], "--sendto") == 0) - { - if (i < argc - 1) - { - i++; - - opt->send_to_srv = 1; - - set_output_format(opt, "bin"); - - opt->xmltv = 2; - opt->xmltvliveinterval = 2; - - char *addr = argv[i]; - if (*addr == '[') - { - addr++; - - opt->srv_addr = addr; - - char *br = strchr(addr, ']'); - if (br == NULL) - { - fatal(EXIT_INCOMPATIBLE_PARAMETERS, "Wrong address format, for IPv6 use [address]:port\n"); - } - *br = '\0'; - - br++; /* Colon */ - if (*br != '\0') - { - opt->srv_port = br + 1; - } - - continue; - } - - opt->srv_addr = argv[i]; - - char *colon = strchr(argv[i], ':'); - if (colon != NULL) - { - *colon = '\0'; - opt->srv_port = colon + 1; - } - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--sendto has no argument.\n"); - } - } - if (strcmp(argv[i], "--tcp") == 0) - { - if (i < argc - 1) - { - i++; - - opt->tcpport = argv[i]; - opt->input_source = CCX_DS_TCP; - - set_input_format(opt, "bin"); - - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--tcp has no argument.\n"); - } - } - if (strcmp(argv[i], "--tcp-password") == 0) - { - if (i < argc - 1) - { - i++; - opt->tcp_password = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--tcp-password has no argument.\n"); - } - } - if (strcmp(argv[i], "--tcp-description") == 0) - { - if (i < argc - 1) - { - i++; - opt->tcp_desc = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--tcpdesc has no argument.\n"); - } - } - - if (strcmp(argv[i], "--font") == 0) - { - if (i < argc - 1) - { - i++; - opt->enc_cfg.render_font = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--font has no argument.\n"); - } - } - if (strcmp(argv[i], "--italics") == 0 && i < argc - 1) - { - opt->enc_cfg.render_font_italics = argv[i + 1]; - i++; - continue; - } - -#ifdef WITH_LIBCURL - if (strcmp(argv[i], "--curlposturl") == 0) - { - if (i < argc - 1) - { - i++; - opt->curlposturl = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--curlposturl has no argument.\n"); - } - } -#endif // WITH_LIBCURL - - fatal(EXIT_INCOMPATIBLE_PARAMETERS, "Error: Parameter %s not understood.\n", argv[i]); - } - - if (opt->demux_cfg.auto_stream == CCX_SM_MP4 && opt->input_source == CCX_DS_STDIN) - { - fatal(EXIT_INCOMPATIBLE_PARAMETERS, "MP4 requires an actual file, it's not possible to read from a stream, including stdin.\n"); - } - - if (opt->extract_chapters) - { - mprint("Request to extract chapters recieved.\n"); - mprint("Note that this must only be used with MP4 files,\n"); - mprint("for other files it will simply generate subtitles file.\n\n"); - } - - if (opt->gui_mode_reports) - { - opt->no_progress_bar = 1; - // Do it as soon as possible, because it something fails we might not have a chance - activity_report_version(); - } - - if (opt->enc_cfg.sentence_cap) - { - if (add_builtin_words(capitalized_builtin, &capitalization_list)) - fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory for capitalized word list"); - if (opt->sentence_cap_file && process_word_file(opt->sentence_cap_file, &capitalization_list)) - fatal(EXIT_ERROR_IN_CAPITALIZATION_FILE, "There was an error processing the capitalization file.\n"); - } - - if (opt->enc_cfg.filter_profanity) - { - if (add_builtin_words(profane_builtin, &profane)) - fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory for profane word list"); - if (opt->filter_profanity_file && process_word_file(opt->filter_profanity_file, &profane)) - fatal(EXIT_ERROR_IN_CAPITALIZATION_FILE, "There was an error processing the profanity file.\n"); - } - - ccx_encoders_helpers_perform_shellsort_words(); // Sort the words for binary search for capitalization and profanity censorship - - if (opt->demux_cfg.ts_forced_program != -1) - opt->demux_cfg.ts_forced_program_selected = 1; - - // Init telexcc redundant options - tlt_config.dolevdist = opt->dolevdist; - tlt_config.levdistmincnt = opt->levdistmincnt; - tlt_config.levdistmaxpct = opt->levdistmaxpct; - tlt_config.extraction_start = opt->extraction_start; - tlt_config.extraction_end = opt->extraction_end; - tlt_config.write_format = opt->write_format; - tlt_config.gui_mode_reports = opt->gui_mode_reports; - tlt_config.date_format = opt->date_format; - tlt_config.noautotimeref = opt->noautotimeref; - tlt_config.send_to_srv = opt->send_to_srv; - tlt_config.nofontcolor = opt->nofontcolor; - tlt_config.nohtmlescape = opt->nohtmlescape; - tlt_config.millis_separator = opt->millis_separator; - - // teletext page number out of range - if (tlt_config.page != 0 && (tlt_config.page < 100 || tlt_config.page > 899)) - { - print_error(opt->gui_mode_reports, "Teletext page number could not be lower than 100 or higher than 899\n"); - return EXIT_NOT_CLASSIFIED; - } - - if (opt->num_input_files == 0 && opt->input_source == CCX_DS_FILE) - { - return EXIT_NO_INPUT_FILES; - } - if (opt->num_input_files > 1 && opt->live_stream) - { - print_error(opt->gui_mode_reports, "Live stream mode accepts only one input file.\n"); - return EXIT_TOO_MANY_INPUT_FILES; - } - if (opt->num_input_files && opt->input_source == CCX_DS_NETWORK) - { - print_error(opt->gui_mode_reports, "UDP mode is not compatible with input files.\n"); - return EXIT_TOO_MANY_INPUT_FILES; - } - if (opt->input_source == CCX_DS_NETWORK || opt->input_source == CCX_DS_TCP) - { - ccx_options.buffer_input = 1; // Mandatory, because each datagram must be read complete. - } - if (opt->num_input_files && opt->input_source == CCX_DS_TCP) - { - print_error(opt->gui_mode_reports, "TCP mode is not compatible with input files.\n"); - return EXIT_TOO_MANY_INPUT_FILES; - } - - if (opt->demux_cfg.auto_stream == CCX_SM_MCPOODLESRAW && opt->write_format == CCX_OF_RAW) - { - print_error(opt->gui_mode_reports, "-in=raw can only be used if the output is a subtitle file.\n"); - return EXIT_INCOMPATIBLE_PARAMETERS; - } - if (opt->demux_cfg.auto_stream == CCX_SM_RCWT && opt->write_format == CCX_OF_RCWT && opt->output_filename == NULL) - { - print_error(opt->gui_mode_reports, - "CCExtractor's binary format can only be used simultaneously for input and\noutput if the output file name is specified given with -o.\n"); - return EXIT_INCOMPATIBLE_PARAMETERS; - } - if (opt->write_format != CCX_OF_DVDRAW && opt->cc_to_stdout && opt->extract == 12) - { - print_error(opt->gui_mode_reports, "You can't extract both fields to stdout at the same time in broadcast mode.\n"); - return EXIT_INCOMPATIBLE_PARAMETERS; - } - if (opt->write_format == CCX_OF_SPUPNG && opt->cc_to_stdout) - { - print_error(opt->gui_mode_reports, "You cannot use --out=spupng with -stdout.\n"); - return EXIT_INCOMPATIBLE_PARAMETERS; - } - - if (opt->write_format == CCX_OF_WEBVTT && opt->enc_cfg.encoding != CCX_ENC_UTF_8) - { - mprint("Note: Output format is WebVTT, forcing UTF-8\n"); - opt->enc_cfg.encoding = CCX_ENC_UTF_8; - } -#ifdef WITH_LIBCURL - if (opt->write_format == CCX_OF_CURL && opt->curlposturl == NULL) - { - print_error(opt->gui_mode_reports, "You must pass a URL (-curlposturl) if output format is curl\n"); - return EXIT_INCOMPATIBLE_PARAMETERS; - } - if (opt->write_format != CCX_OF_CURL && opt->curlposturl != NULL) - { - print_error(opt->gui_mode_reports, "-curlposturl requires that the format is curl\n"); - return EXIT_INCOMPATIBLE_PARAMETERS; - } -#endif // WITH_LIBCURL - /* Initialize some Encoder Configuration */ - opt->enc_cfg.extract = opt->extract; - if (opt->num_input_files > 0) - { - opt->enc_cfg.multiple_files = 1; - opt->enc_cfg.first_input_file = opt->inputfile[0]; - } - opt->enc_cfg.cc_to_stdout = opt->cc_to_stdout; - opt->enc_cfg.write_format = opt->write_format; - opt->enc_cfg.send_to_srv = opt->send_to_srv; - opt->enc_cfg.date_format = opt->date_format; - opt->enc_cfg.transcript_settings = opt->transcript_settings; - opt->enc_cfg.millis_separator = opt->millis_separator; - opt->enc_cfg.no_font_color = opt->nofontcolor; - opt->enc_cfg.force_flush = opt->force_flush; - opt->enc_cfg.append_mode = opt->append_mode; - opt->enc_cfg.ucla = opt->ucla; - opt->enc_cfg.no_type_setting = opt->notypesetting; - opt->enc_cfg.subs_delay = opt->subs_delay; - opt->enc_cfg.gui_mode_reports = opt->gui_mode_reports; - if (opt->enc_cfg.render_font == NULL) - { - opt->enc_cfg.render_font = DEFAULT_FONT_PATH; - } - if (opt->enc_cfg.render_font_italics == NULL) - { - opt->enc_cfg.render_font_italics = DEFAULT_FONT_PATH_ITALICS; - } - if (opt->output_filename && opt->multiprogram == CCX_FALSE) - { - opt->enc_cfg.output_filename = strdup(opt->output_filename); - } - else - { - opt->enc_cfg.output_filename = NULL; - } - - if (!opt->is_608_enabled && !opt->is_708_enabled) - { - // If nothing is selected then extract both 608 and 708 subs - - // 608 field 1 is enabled by default - // Enable 708 subs extraction - parse_708_services(opt, "all"); - } - else if (!opt->is_608_enabled && opt->is_708_enabled) - { - // Extract only 708 subs - - // 608 field 1 is enabled by default, disable it - opt->extract = 0; - opt->enc_cfg.extract_only_708 = 1; - } - -#ifdef WITH_LIBCURL - opt->enc_cfg.curlposturl = opt->curlposturl; -#endif - return EXIT_OK; -} diff --git a/src/lib_ccx/utility.c b/src/lib_ccx/utility.c index 9714a1627..960ea0046 100644 --- a/src/lib_ccx/utility.c +++ b/src/lib_ccx/utility.c @@ -9,7 +9,6 @@ int temp_debug = 0; // This is a convenience variable used to enable/disable debug on variable conditions. Find references to understand. volatile sig_atomic_t change_filename_requested = 0; -#ifndef DISABLE_RUST extern int ccxr_verify_crc32(uint8_t *buf, int len); extern int ccxr_levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len); extern int ccxr_levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsigned s2len); @@ -17,7 +16,6 @@ extern void ccxr_timestamp_to_srttime(uint64_t timestamp, char *buffer); extern void ccxr_timestamp_to_vtttime(uint64_t timestamp, char *buffer); extern void ccxr_millis_to_date(uint64_t timestamp, char *buffer, enum ccx_output_date_format date_format, char millis_separator); extern int ccxr_stringztoms(const char *s, struct ccx_boundary_time *bt); -#endif static uint32_t crc32_table[] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, @@ -87,182 +85,37 @@ static uint32_t crc32_table[] = { int verify_crc32(uint8_t *buf, int len) { -#ifndef DISABLE_RUST return ccxr_verify_crc32(buf, len); -#endif - - int i = 0; - int32_t crc = -1; - for (i = 0; i < len; i++) - crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (buf[i] & 0xff)) & 0xff]; - return crc ? CCX_FALSE : CCX_TRUE; } int stringztoms(const char *s, struct ccx_boundary_time *bt) { -#ifndef DISABLE_RUST return ccxr_stringztoms(s, bt); -#endif - - unsigned ss = 0, mm = 0, hh = 0; - int value = -1; - int colons = 0; - const char *c = s; - while (*c) - { - if (*c == ':') - { - if (value == -1) // : at the start, or ::, etc - return -1; - colons++; - if (colons > 2) // Max 2, for HH:MM:SS - return -1; - hh = mm; - mm = ss; - ss = value; - value = -1; - } - else - { - if (!isdigit(*c)) // Only : or digits, so error - return -1; - if (value == -1) - value = *c - '0'; - else - value = value * 10 + *c - '0'; - } - c++; - } - hh = mm; - mm = ss; - ss = value; - if (mm > 59 || ss > 59) - return -1; - bt->set = 1; - bt->hh = hh; - bt->mm = mm; - bt->ss = ss; - LLONG secs = (hh * 3600 + mm * 60 + ss); - bt->time_in_ms = secs * 1000; - return 0; } void timestamp_to_srttime(uint64_t timestamp, char *buffer) { -#ifndef DISABLE_RUST return ccxr_timestamp_to_srttime(timestamp, buffer); -#endif - - uint64_t p = timestamp; - uint8_t h = (uint8_t)(p / 3600000); - uint8_t m = (uint8_t)(p / 60000 - 60 * h); - uint8_t s = (uint8_t)(p / 1000 - 3600 * h - 60 * m); - uint16_t u = (uint16_t)(p - 3600000 * h - 60000 * m - 1000 * s); - sprintf(buffer, "%02" PRIu8 ":%02" PRIu8 ":%02" PRIu8 ",%03" PRIu16, h, m, s, u); } void timestamp_to_vtttime(uint64_t timestamp, char *buffer) { -#ifndef DISABLE_RUST return ccxr_timestamp_to_vtttime(timestamp, buffer); -#endif - - uint64_t p = timestamp; - uint8_t h = (uint8_t)(p / 3600000); - uint8_t m = (uint8_t)(p / 60000 - 60 * h); - uint8_t s = (uint8_t)(p / 1000 - 3600 * h - 60 * m); - uint16_t u = (uint16_t)(p - 3600000 * h - 60000 * m - 1000 * s); - sprintf(buffer, "%02" PRIu8 ":%02" PRIu8 ":%02" PRIu8 ".%03" PRIu16, h, m, s, u); } #define MIN3(a, b, c) ((a) < (b) ? ((a) < (c) ? (a) : (c)) : ((b) < (c) ? (b) : (c))) int levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len) { -#ifndef DISABLE_RUST return ccxr_levenshtein_dist(s1, s2, s1len, s2len); -#endif - - unsigned int x, y, v, lastdiag, olddiag; - unsigned int *column = (unsigned *)malloc((s1len + 1) * sizeof(unsigned int)); - for (y = 1; y <= s1len; y++) - column[y] = y; - for (x = 1; x <= s2len; x++) - { - column[0] = x; - for (y = 1, lastdiag = x - 1; y <= s1len; y++) - { - olddiag = column[y]; - column[y] = MIN3(column[y] + 1, column[y - 1] + 1, lastdiag + (s1[y - 1] == s2[x - 1] ? 0 : 1)); - lastdiag = olddiag; - } - } - v = column[s1len]; - free(column); - return v; } int levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsigned s2len) { -#ifndef DISABLE_RUST return ccxr_levenshtein_dist_char(s1, s2, s1len, s2len); -#endif - unsigned int x, y, v, lastdiag, olddiag; - unsigned int *column = (unsigned *)malloc((s1len + 1) * sizeof(unsigned int)); - for (y = 1; y <= s1len; y++) - column[y] = y; - for (x = 1; x <= s2len; x++) - { - column[0] = x; - for (y = 1, lastdiag = x - 1; y <= s1len; y++) - { - olddiag = column[y]; - column[y] = MIN3(column[y] + 1, column[y - 1] + 1, lastdiag + (s1[y - 1] == s2[x - 1] ? 0 : 1)); - lastdiag = olddiag; - } - } - v = column[s1len]; - free(column); - return v; } void millis_to_date(uint64_t timestamp, char *buffer, enum ccx_output_date_format date_format, char millis_separator) { -#ifndef DISABLE_RUST return ccxr_millis_to_date(timestamp, buffer, date_format, millis_separator); -#endif - - time_t secs; - unsigned int millis; - char c_temp[80]; - struct tm *time_struct = NULL; - switch (date_format) - { - case ODF_NONE: - buffer[0] = 0; - break; - case ODF_HHMMSS: - timestamp_to_srttime(timestamp, buffer); - buffer[8] = 0; - break; - case ODF_HHMMSSMS: - timestamp_to_srttime(timestamp, buffer); - break; - case ODF_SECONDS: - secs = (time_t)(timestamp / 1000); - millis = (time_t)(timestamp % 1000); - sprintf(buffer, "%lu%c%03u", (unsigned long)secs, - millis_separator, (unsigned)millis); - break; - case ODF_DATE: - secs = (time_t)(timestamp / 1000); - millis = (unsigned int)(timestamp % 1000); - time_struct = gmtime(&secs); - strftime(c_temp, sizeof(c_temp), "%Y%m%d%H%M%S", time_struct); - sprintf(buffer, "%s%c%03u", c_temp, millis_separator, millis); - break; - - default: - fatal(CCX_COMMON_EXIT_BUG_BUG, "Invalid value for date_format in millis_to_date()\n"); - } } bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) diff --git a/src/lib_ccx/utility.h b/src/lib_ccx/utility.h index 6fc6eafa1..0c3a6867f 100644 --- a/src/lib_ccx/utility.h +++ b/src/lib_ccx/utility.h @@ -26,7 +26,6 @@ struct ccx_rational extern int temp_debug; volatile extern sig_atomic_t change_filename_requested; -#ifndef DISABLE_RUST extern int ccxr_verify_crc32(uint8_t *buf, int len); extern int ccxr_levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len); extern int ccxr_levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsigned s2len); @@ -34,7 +33,6 @@ extern void ccxr_timestamp_to_srttime(uint64_t timestamp, char *buffer); extern void ccxr_timestamp_to_vtttime(uint64_t timestamp, char *buffer); extern void ccxr_millis_to_date(uint64_t timestamp, char *buffer, enum ccx_output_date_format date_format, char millis_separator); extern int ccxr_stringztoms(const char *s, struct ccx_boundary_time *bt); -#endif int levenshtein_dist_char (const char *s1, const char *s2, unsigned s1len, unsigned s2len); void init_boundary_time (struct ccx_boundary_time *bt);