[FEAT] Removed C code already ported to Rust (#1738)

* Removal: Removed redundant C code already ported to Rust

* Removal: C formatting

* Removal: More Removal and CI issues in Mac

* Removal: CI issues in Mac

* Removal: Changes due to Rebase

* Removal: Failing CI on mac

* Removal: Failing regression test on dvdraw
This commit is contained in:
Deepnarayan Sett
2025-09-06 20:16:39 +05:30
committed by GitHub
parent 3f441150b4
commit ba59eb0887
28 changed files with 200 additions and 4218 deletions

View File

@@ -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:

View File

@@ -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/

View File

@@ -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=

View File

@@ -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; }
cp $RUST_LIB ./libccx_rust.a
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; }
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=$?

View File

@@ -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=

View File

@@ -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

View File

@@ -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})

View File

@@ -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)
{

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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 */

View File

@@ -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, ...);

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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_*/

View File

@@ -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

View File

@@ -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
}
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -1,346 +1,2 @@
#include "lib_ccx.h"
#include "utility.h"
#if defined(ENABLE_HARDSUBX) && defined(DISABLE_RUST)
// TODO: Correct FFMpeg integration
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <leptonica/allheaders.h>
#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("<i>") + 2);
strcpy(word, "<i>");
strcat(word, word_copy);
free(word_copy);
prev_ital = 1;
}
else if (italic == 0 && prev_ital == 1)
{
word = realloc(word, strlen(word) + strlen("</i>") + 2);
strcat(word, "</i>");
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("<i>") + 2);
strcpy(word, "<i>");
strcat(word, word_copy);
free(word_copy);
prev_ital = 1;
}
else if (italic == 0 && prev_ital == 1)
{
word = realloc(word, strlen(word) + strlen("</i>") + 2);
strcat(word, "</i>");
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("</i>") + 2);
strcat(text_out, "</i>");
}
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("<i>") + 2);
strcpy(word, "<i>");
strcat(word, word_copy);
free(word_copy);
prev_ital = 1;
}
else if (italic == 0 && prev_ital == 1)
{
word = realloc(word, strlen(word) + strlen("</i>") + 2);
strcat(word, "</i>");
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("<i>") + 2);
strcpy(word, "<i>");
strcat(word, word_copy);
free(word_copy);
prev_ital = 1;
}
else if (italic == 0 && prev_ital == 1)
{
word = realloc(word, strlen(word) + strlen("</i>") + 2);
strcat(word, "</i>");
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("</i>") + 2);
strcat(text_out, "</i>");
}
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

View File

@@ -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

View File

@@ -1,116 +1,2 @@
#include "lib_ccx.h"
#include "utility.h"
#if defined(ENABLE_HARDSUBX) && defined(DISABLE_RUST)
// TODO: Correct FFMpeg integration
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <leptonica/allheaders.h>
#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

View File

@@ -1,132 +1,2 @@
#include "lib_ccx.h"
#include "utility.h"
#if defined(ENABLE_HARDSUBX) && defined(DISABLE_RUST)
// TODO: Correct FFMpeg integration
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <leptonica/allheaders.h>
#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

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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)

View File

@@ -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);