mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-02-10 05:31:32 +00:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f00cec9c0 | ||
|
|
b7d2754518 | ||
|
|
94675b2dac | ||
|
|
2c9faa70ea | ||
|
|
b7616fcb17 | ||
|
|
eb93345544 | ||
|
|
e6024c1cb1 | ||
|
|
ecc4c2520e | ||
|
|
a83c686f6a | ||
|
|
c4a8135b4d | ||
|
|
004f9d512a | ||
|
|
53df68b4c3 | ||
|
|
74bb91aa5b | ||
|
|
453bb56520 | ||
|
|
db50730a00 | ||
|
|
36a266e43c | ||
|
|
354c52ec61 | ||
|
|
2b65419bfb | ||
|
|
740365db7e | ||
|
|
03dc0498ea | ||
|
|
e9a7474f3d | ||
|
|
1ecb2abd62 | ||
|
|
d3b4b8ff03 | ||
|
|
29aa63c23c | ||
|
|
7083a36ecb | ||
|
|
38421e886e | ||
|
|
b0de53c351 | ||
|
|
09dcb8b7c0 | ||
|
|
13ab9e6a4e | ||
|
|
08ae34bc24 | ||
|
|
f5f1a70eb8 | ||
|
|
471c130928 | ||
|
|
4db37e7ac3 | ||
|
|
3953f806b0 | ||
|
|
cf0ebd27f7 | ||
|
|
559d05c478 | ||
|
|
4d7e629ba5 | ||
|
|
866c4ea159 | ||
|
|
cf508653f2 | ||
|
|
b3b683aa83 | ||
|
|
9f6309ef14 | ||
|
|
b95e06c21c | ||
|
|
7ed99097ba | ||
|
|
3f4bbbde25 | ||
|
|
5828f50210 | ||
|
|
b5931e8749 | ||
|
|
c588b42e0a | ||
|
|
f9ee9570a4 | ||
|
|
55e408bbb7 | ||
|
|
93a5ae9728 | ||
|
|
5c7430cff5 | ||
|
|
fecf14bc15 | ||
|
|
a4275eba62 | ||
|
|
3873e8fd30 | ||
|
|
5e22be2576 | ||
|
|
0b568cb168 | ||
|
|
017d539710 | ||
|
|
06c8f69056 | ||
|
|
b06654b760 | ||
|
|
4ff49c2010 | ||
|
|
0c650711cf | ||
|
|
3128f10fb5 | ||
|
|
63b209929e | ||
|
|
5f68a9166f | ||
|
|
15616edea8 | ||
|
|
cce4ec5e1a | ||
|
|
72ecd279cf | ||
|
|
87f1a3845c | ||
|
|
4ae5f3483c | ||
|
|
38876690f8 | ||
|
|
7bb4e842dd | ||
|
|
26d9584a93 | ||
|
|
9d5ce9aaae | ||
|
|
47264425df | ||
|
|
e8f8d04369 | ||
|
|
78cb26c9cb | ||
|
|
2f5d45df01 | ||
|
|
53be44dfdb | ||
|
|
48b5a0b384 | ||
|
|
a08c7b1871 | ||
|
|
0a2a00f883 | ||
|
|
2125e58e1f | ||
|
|
5bdd6971f7 | ||
|
|
051bc7138d | ||
|
|
e6dca329ee | ||
|
|
6cfddb12a6 | ||
|
|
c9c063b8d8 | ||
|
|
e0cd8b2e56 | ||
|
|
38d2088db5 | ||
|
|
8e940b050a | ||
|
|
5733b40ca6 | ||
|
|
22c40675a6 | ||
|
|
a3ef46c21d | ||
|
|
93a546bab4 | ||
|
|
ec427fd82c | ||
|
|
70cc3c2046 | ||
|
|
5634960813 | ||
|
|
c7a49e80e3 | ||
|
|
617d2d30dc | ||
|
|
18f781d099 | ||
|
|
84db812769 | ||
|
|
7763f8aeab | ||
|
|
faa879801e | ||
|
|
4635329a5b | ||
|
|
b89cc3b6df | ||
|
|
e9f8313f7c | ||
|
|
324cd84ffe | ||
|
|
9d7518c9ec | ||
|
|
32e0d6023d | ||
|
|
c9465e476b | ||
|
|
45d237da40 |
@@ -4,7 +4,7 @@ MAINTAINER = Marc Espie <espie@openbsd.org>
|
||||
CATEGORIES = multimedia
|
||||
COMMENT = closed caption subtitles extractor
|
||||
HOMEPAGE = http://ccextractor.sourceforge.net/
|
||||
V = 0.71
|
||||
V = 0.75
|
||||
DISTFILES = ccextractor.${V:S/.//}-src.zip
|
||||
MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=ccextractor/}
|
||||
DISTNAME = ccextractor-$V
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
0.75
|
||||
-----------
|
||||
- Fixed issue with teletext to other then srt.
|
||||
- CCExtractor can be used as library if compiled using cmake
|
||||
- By default the Windows version adds BOM to generated UTF files (this is
|
||||
because it's needed to open the files correctly) while all other
|
||||
builds don't add it (because it messes with text processing tools).
|
||||
You can use -bom and -nobom to change the behaviour.
|
||||
|
||||
0.74
|
||||
-----------
|
||||
- Fixed issue with -o1 -o2 and -12 parameters (where it would write output only in the o2 file)
|
||||
- Fixed UCLA parameter issue. Now the UCLA parameter settings can't be overwritten anymore by later parameters that affect the custom transcript
|
||||
- Switched order around for TLT and TT page number in custom transcript to match UCLA settings
|
||||
- Added nobom parameter, for when files are processed by tools that can't handle the BOM. If using this, files might be not readable under windows.
|
||||
- Segfault fix when no input files were given
|
||||
- No more bin output when sending to server + possibility to send TT to server for processing
|
||||
- Windows: Added the Microsoft redistributable MSVCR120.DLL to both the installation package and the application zip.
|
||||
|
||||
0.73 - GSOC
|
||||
-----------
|
||||
- Added support of BIN format for Teletext
|
||||
|
||||
@@ -6,8 +6,8 @@ extract text from images. In the World of Subtile, subtitle stored
|
||||
in bitmap format are common and even neccassary. for converting subtile
|
||||
in bitmap format to subtilte in text format ocr is used.
|
||||
|
||||
Dependecy
|
||||
=========
|
||||
Dependency
|
||||
==========
|
||||
Tesseract (OCR library by google)
|
||||
Leptonica (image processing library)
|
||||
|
||||
@@ -55,7 +55,7 @@ make ENABLE_OCR=yes
|
||||
|
||||
|
||||
How to compile ccextractor on Windows with OCR
|
||||
=============================================
|
||||
===============================================
|
||||
|
||||
Download prebuild library of leptonica from following link
|
||||
http://www.leptonica.com/source/leptonica-1.68-win32-lib-include-dirs.zip
|
||||
@@ -90,7 +90,7 @@ Step 7)Add liblept168.lib in new line
|
||||
|
||||
Download language data from following link
|
||||
https://code.google.com/p/tesseract-ocr/downloads/list
|
||||
after downloading the tesseract-ocr-3.02.eng.tar extract the tar file and put
|
||||
after downloading the tesseract-ocr-3.02.eng.tar.gz extract the tar file and put
|
||||
tessdata folder where you have kept ccextractor executable
|
||||
|
||||
Copy the tesseract and leptonica dll in the folder of executable or in system32.
|
||||
@@ -1,4 +1,4 @@
|
||||
ccextractor, 0.73
|
||||
ccextractor, 0.75
|
||||
-----------------
|
||||
Authors: Carlos Fernández (cfsmp3), Volker Quetschke.
|
||||
Maintainer: cfsmp3
|
||||
|
||||
28
docs/using_cmake_build.txt
Normal file
28
docs/using_cmake_build.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
For building ccextractor using cmake folllow below steps..
|
||||
|
||||
Step 1) Check you have right version of cmake installed. ( version >= 3.0.2 )
|
||||
We are using CMP0037 policy of cmake which was introduced in 3.0.0
|
||||
since we have tested our system only with cmake version 3.0.2, I would
|
||||
suggest to use 3.0.2 or higher version.
|
||||
|
||||
|
||||
Step 2) create a seprate directory where you want to build the target.
|
||||
In Unix you can do it using follwing commands.
|
||||
~> cd ccextractor
|
||||
~> mkdir build
|
||||
|
||||
Step 3) make the build sytem using cmake
|
||||
~> cmake ../src/
|
||||
|
||||
Step 4) Compile the code.
|
||||
~> make
|
||||
~> make install
|
||||
|
||||
Step 5) Use CCextractor as you would like
|
||||
|
||||
|
||||
If you want to build CCExtractor with FFMpeg you need to pass
|
||||
cmake -DWITH_FFMPEG=ON ../src/
|
||||
|
||||
Hint for looking all the things you want to set from outside
|
||||
cmake -LAH ../src/
|
||||
@@ -3,7 +3,7 @@ SHELL = /bin/sh
|
||||
CC = gcc
|
||||
SYS := $(shell gcc -dumpmachine)
|
||||
CFLAGS = -O3 -std=gnu99
|
||||
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib
|
||||
INCLUDE = -I../src/gpacmp4/ -I../src/libpng -I../src/zlib -I../src/lib_ccx -I../src/.
|
||||
ALL_FLAGS = -Wno-write-strings -D_FILE_OFFSET_BITS=64
|
||||
LDFLAGS = -lm
|
||||
|
||||
@@ -13,12 +13,16 @@ endif
|
||||
TARGET = ccextractor
|
||||
|
||||
OBJS_DIR = objs
|
||||
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib
|
||||
VPATH = ../src:../src/gpacmp4:../src/libpng:../src/zlib:../src/lib_ccx
|
||||
|
||||
SRCS_DIR = ../src
|
||||
SRCS_C = $(wildcard $(SRCS_DIR)/*.c)
|
||||
OBJS = $(SRCS_C:$(SRCS_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
|
||||
SRCS_CCX_DIR = $(SRCS_DIR)/lib_ccx
|
||||
SRCS_CCX = $(wildcard $(SRCS_CCX_DIR)/*.c)
|
||||
OBJS_CCX = $(SRCS_CCX:$(SRCS_CCX_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
|
||||
SRCS_PNG_DIR = $(SRCS_DIR)/libpng
|
||||
SRCS_PNG = $(wildcard $(SRCS_PNG_DIR)/*.c)
|
||||
OBJS_PNG = $(SRCS_PNG:$(SRCS_PNG_DIR)/%.c=$(OBJS_DIR)/%.o)
|
||||
@@ -38,10 +42,31 @@ INSTLALL_PROGRAM = $(INSTLALL)
|
||||
DESTDIR = /usr/bin
|
||||
|
||||
ifeq ($(ENABLE_OCR),yes)
|
||||
CFLAGS+=-I/usr/local/include/tesseract -I/usr/local/include/leptonica
|
||||
CFLAGS+=-DENABLE_OCR
|
||||
LDFLAGS+= $(shell pkg-config --libs tesseract)
|
||||
TESS_LDFLAGS+= $(shell pkg-config --libs tesseract)
|
||||
LEPT_LDFLAGS+= $(shell pkg-config --libs lept)
|
||||
|
||||
#error checking of library are there or not
|
||||
ifeq ($(TESS_LDFLAGS),$(EMPTY))
|
||||
$(error **ERROR** "tesseract not found")
|
||||
else
|
||||
#TODO print the version of library found
|
||||
$(info "tesseract found")
|
||||
endif
|
||||
ifeq ($(LEPT_LDFLAGS),$(EMPTY))
|
||||
$(error **ERROR** "leptonica not found")
|
||||
else
|
||||
#TODO print the version of library found
|
||||
$(info "Leptonica found")
|
||||
endif
|
||||
|
||||
CFLAGS += $(shell pkg-config --cflags tesseract)
|
||||
CFLAGS += $(shell pkg-config --cflags lept)
|
||||
LDFLAGS += $(TESS_LDFLAGS)
|
||||
LDFLAGS += $(LEPT_LDFLAGS)
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(ENABLE_FFMPEG),yes)
|
||||
CFLAGS+=-DENABLE_FFMPEG
|
||||
CFLAGS+= $(shell pkg-config --cflags libavcodec)
|
||||
@@ -59,8 +84,8 @@ all: objs_dir $(TARGET)
|
||||
objs_dir:
|
||||
mkdir -p $(OBJS_DIR)
|
||||
|
||||
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB)
|
||||
$(CC) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
$(TARGET): $(OBJS) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(OBJS_CCX)
|
||||
$(CC) $(ALL_FLAGS) $(CFLAGS) $(OBJS) $(OBJS_CCX) $(OBJS_PNG) $(OBJS_GPACMP4) $(OBJS_ZLIB) $(LDFLAGS) -o $@
|
||||
|
||||
$(OBJS_DIR)/%.o: %.c
|
||||
$(CC) -c $(ALL_FLAGS) $(INCLUDE) $(CFLAGS) $< -o $@
|
||||
@@ -71,7 +96,7 @@ $(OBJS_DIR)/%.o: %.cpp
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm $(TARGET) 2>/dev/null || true
|
||||
rm $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
|
||||
rm $(OBJS_CCX) $(OBJS_PNG) $(OBJS_ZLIB) $(OBJS_GPACMP4) $(OBJS) 2>/dev/null || true
|
||||
rm -rd $(OBJS_DIR) 2>/dev/null || true
|
||||
rm .depend 2>/dev/null || true
|
||||
|
||||
@@ -85,7 +110,7 @@ uninstall:
|
||||
|
||||
.PHONY: depend dep
|
||||
depend dep:
|
||||
$(CC) $(CFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) \
|
||||
$(CC) $(CFLAGS) -E -MM $(SRCS_C) $(SRCS_PNG) $(SRCS_ZLIB) $(SRCS_CXX) \
|
||||
$(SRCS_GPACMP4_C) $(SRCS_GPACMP4_CPP) |\
|
||||
sed 's/^[a-zA-Z_0-9]*.o/$(OBJS_DIR)\/&/' > .depend
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/bash
|
||||
gcc -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64 -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
|
||||
gcc -std=gnu99 -Wno-write-strings -DGPAC_CONFIG_LINUX -D_FILE_OFFSET_BITS=64 -I../src/lib_ccx/ -I../src/gpacmp4/ -I../src/libpng/ -I../src/zlib/ -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c') -lm -zmuldefs
|
||||
|
||||
@@ -1 +1 @@
|
||||
gcc -std=gnu99 -Wno-write-strings -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I../src/gpacmp4 -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c')
|
||||
gcc -std=gnu99 -Wno-write-strings -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -I ../src/gpacmp4 -I ../src/lib_ccx -I ../src/libpng -I ../src/zlib -o ccextractor $(find ../src/ -name '*.cpp') $(find ../src/ -name '*.c')
|
||||
|
||||
285
src/608_sami.c
285
src/608_sami.c
@@ -1,285 +0,0 @@
|
||||
#include "ccextractor.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
|
||||
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)ms_start);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_br, encoded_br_length);
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used=encode_line (context->buffer,(unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)ms_end);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
write(context->out->fh, context->buffer, used);
|
||||
free(el);
|
||||
free(unescaped);
|
||||
}
|
||||
|
||||
|
||||
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
//char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
//int used;
|
||||
#ifdef ENABLE_OCR
|
||||
unsigned h1, m1, s1, ms1;
|
||||
unsigned h2, m2, s2, ms2;
|
||||
#endif
|
||||
LLONG ms_start, ms_end;
|
||||
//char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start + subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = sub->start_time + subs_delay;
|
||||
ms_end = sub->end_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
char *token = NULL;
|
||||
sprintf(context->buffer,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
|
||||
,(unsigned long long)ms_start);
|
||||
write(context->out->fh,context->buffer,strlen(context->buffer));
|
||||
token = strtok(str,"\r\n");
|
||||
while (token)
|
||||
{
|
||||
|
||||
sprintf(context->buffer,"%s",token);
|
||||
token = strtok(NULL,"\r\n");
|
||||
if(token)
|
||||
strcat(context->buffer,"<br>\n");
|
||||
else
|
||||
strcat(context->buffer,"\n");
|
||||
write(context->out->fh,context->buffer,strlen(context->buffer));
|
||||
|
||||
}
|
||||
sprintf(context->buffer,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n"
|
||||
,(unsigned long long)ms_end);
|
||||
write(context->out->fh,context->buffer,strlen(context->buffer));
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
LLONG startms, endms;
|
||||
int wrote_something=0;
|
||||
startms = data->start_time;
|
||||
|
||||
startms+=subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
endms = data->end_time;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)startms);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
}
|
||||
write (context->out->fh, subline, length);
|
||||
wrote_something=1;
|
||||
if (i!=14)
|
||||
write (context->out->fh, encoded_br, encoded_br_length);
|
||||
write (context->out->fh,encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)endms);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
return wrote_something;
|
||||
}
|
||||
6
src/CCExtractorConfig.h.in
Normal file
6
src/CCExtractorConfig.h.in
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* the configured options and settings for CCExtractor
|
||||
*/
|
||||
|
||||
#define CCExtractor_VERSION_MAJOR @CCEXTRACTOR_VERSION_MAJOR@
|
||||
#define CCExtractor_VERSION_MINOR @CCEXTRACTOR_VERSION_MINOR@
|
||||
54
src/CMakeLists.txt
Normal file
54
src/CMakeLists.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
cmake_minimum_required (VERSION 3.0.2)
|
||||
|
||||
project (CCExtractor)
|
||||
|
||||
option(WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF)
|
||||
#Version number
|
||||
set (CCEXTRACTOR_VERSION_MAJOR 0)
|
||||
set (CCEXTRACTOR_VERSION_MINOR 75)
|
||||
|
||||
# configure a header file to pass some of the CMake settings
|
||||
# to the source code
|
||||
configure_file (
|
||||
"${PROJECT_SOURCE_DIR}/CCExtractorConfig.h.in"
|
||||
"${PROJECT_BINARY_DIR}/CCExtractorConfig.h"
|
||||
)
|
||||
|
||||
|
||||
include_directories ("${PROJECT_SOURCE_DIR}")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/lib_ccx")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/gpacmp4/")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/libccx_common/")
|
||||
|
||||
#Adding some platform specific library path
|
||||
LINK_DIRECTORIES(/opt/local/lib)
|
||||
LINK_DIRECTORIES(/usr/local/lib)
|
||||
|
||||
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -g -std=gnu99 -Wno-write-strings -D_FILE_OFFSET_BITS=64")
|
||||
add_subdirectory (lib_ccx)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} SOURCEFILE)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ccx)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} png)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} m)
|
||||
|
||||
########################################################
|
||||
# Build using FFmpeg libraries
|
||||
#
|
||||
if (WITH_FFMPEG)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(AVFORMAT REQUIRED libavformat)
|
||||
pkg_check_modules(AVUTIL REQUIRED libavutil)
|
||||
pkg_check_modules(AVCODEC REQUIRED libavcodec)
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVFORMAT_STATIC_LIBRARIES} )
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVUTIL_STATIC_LIBRARIES} )
|
||||
set (EXTRA_LIBS ${EXTRA_LIBS} ${AVCODEC_STATIC_LIBRARIES} )
|
||||
|
||||
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
|
||||
endif (WITH_FFMPEG)
|
||||
|
||||
add_executable(ccextractor ${SOURCEFILE})
|
||||
target_link_libraries (ccextractor ${EXTRA_LIBS})
|
||||
|
||||
install (TARGETS ccextractor DESTINATION bin)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,480 +0,0 @@
|
||||
#ifndef CCX_CCEXTRACTOR_H
|
||||
#define CCX_CCEXTRACTOR_H
|
||||
|
||||
#define VERSION "0.73"
|
||||
|
||||
// Load common includes and constants for library usage
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "ccx_common_char_encoding.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_common_timing.h"
|
||||
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_decoders_xds.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "bitstream.h"
|
||||
|
||||
#include "networking.h"
|
||||
|
||||
extern int cc_buffer_saved; // Do we have anything in the CC buffer already?
|
||||
extern int ccblocks_in_avc_total; // Total CC blocks found by the AVC code
|
||||
extern int ccblocks_in_avc_lost; // CC blocks found by the AVC code lost due to overwrites (should be 0)
|
||||
|
||||
#define TS_PMT_MAP_SIZE 128
|
||||
|
||||
struct ccx_boundary_time
|
||||
{
|
||||
int hh,mm,ss;
|
||||
LLONG time_in_ms;
|
||||
int set;
|
||||
};
|
||||
|
||||
struct ccx_s_options // Options from user parameters
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int nofontcolor;
|
||||
int notypesetting;
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
int print_file_reports;
|
||||
|
||||
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
|
||||
|
||||
/* subtitle codec type */
|
||||
enum cxx_code_type codec;
|
||||
enum cxx_code_type nocodec;
|
||||
/* Credit stuff */
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
int binary_concat; // Disabled by -ve or --videoedited
|
||||
int use_gop_as_pts; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
int no_progress_bar; // If 1, suppress the output of the progress to stdout
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
char *sentence_cap_file; // Extra words file?
|
||||
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
|
||||
0 -> A regular file
|
||||
>0 -> Live stream with a timeout of this value in seconds */
|
||||
int messages_target; // 0 = nowhere (quiet), 1=stdout, 2=stderr
|
||||
/* Levenshtein's parameters, for string comparison */
|
||||
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
|
||||
int investigate_packets; // Look for captions in all packets when everything else fails
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
int nosync; // Disable syncing
|
||||
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
int wtvconvertfix; // Fix broken Windows 7 conversion
|
||||
int wtvmpeg2;
|
||||
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
|
||||
/* MP4 related stuff */
|
||||
unsigned mp4vidtrack; // Process the video track even if a CC dedicated track exists.
|
||||
/* General settings */
|
||||
int usepicorder; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
unsigned teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
|
||||
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
char millis_separator;
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
enum ccx_output_date_format date_format;
|
||||
char *output_filename;
|
||||
char *out_elementarystream_filename;
|
||||
LLONG debug_mask; // dbg_print will use this mask to print or ignore different types
|
||||
LLONG debug_mask_on_debug; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
|
||||
unsigned ts_autoprogram ; // Try to find a stream with captions automatically (no -pn needed)
|
||||
unsigned ts_cappid ; // PID for stream that holds caption information
|
||||
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
|
||||
unsigned ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
unsigned ts_forced_program_selected;
|
||||
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
unsigned ts_forced_streamtype; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
char *udpaddr;
|
||||
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
unsigned send_to_srv;
|
||||
char *tcpport;
|
||||
char *tcp_password;
|
||||
char *tcp_desc;
|
||||
char *srv_addr;
|
||||
char *srv_port;
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
int noautotimeref; // Do NOT set time automatically?
|
||||
enum ccx_datasource input_source; // Files, stdin or network
|
||||
|
||||
};
|
||||
|
||||
struct ts_payload
|
||||
{
|
||||
unsigned char *start; // Payload start
|
||||
unsigned length; // Payload length
|
||||
unsigned pesstart; // PES or PSI start
|
||||
unsigned pid; // Stream PID
|
||||
int counter; // continuity counter
|
||||
int transport_error; // 0 = packet OK, non-zero damaged
|
||||
unsigned char section_buf[1024];
|
||||
int section_index;
|
||||
int section_size;
|
||||
};
|
||||
|
||||
struct PAT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned char *last_pmt_payload;
|
||||
unsigned last_pmt_length;
|
||||
};
|
||||
|
||||
struct PMT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned elementary_PID;
|
||||
unsigned ccx_stream_type;
|
||||
unsigned printable_stream_type;
|
||||
};
|
||||
|
||||
/* Report information */
|
||||
#define SUB_STREAMS_CNT 10
|
||||
struct file_report_t
|
||||
{
|
||||
unsigned program_cnt;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned aspect_ratio;
|
||||
unsigned frame_rate;
|
||||
struct ccx_decoder_608_report_t data_from_608;
|
||||
struct ccx_decoder_708_report_t data_from_708;
|
||||
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned mp4_cc_track_cnt;
|
||||
} file_report;
|
||||
|
||||
// Stuff for telcc.c
|
||||
struct ccx_s_teletext_config {
|
||||
uint8_t verbose : 1; // should telxcc be verbose?
|
||||
uint16_t page; // teletext page containing cc we want to filter
|
||||
uint16_t tid; // 13-bit packet ID for teletext stream
|
||||
double offset; // time offset in seconds
|
||||
uint8_t bom : 1; // print UTF-8 BOM characters at the beginning of output
|
||||
uint8_t nonempty : 1; // produce at least one (dummy) frame
|
||||
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
|
||||
// uint64_t utc_refvalue; // UTC referential value => Moved to ccx_decoders_common, so can be used for other decoders (608/xds) too
|
||||
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
|
||||
};
|
||||
|
||||
#define buffered_skip(bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else result=buffered_read_opt (NULL,bytes);
|
||||
|
||||
#define buffered_read(buffer,bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer!=NULL) memcpy (buffer,filebuffer+filebuffer_pos,bytes); \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else { result=buffered_read_opt (buffer,bytes); if (ccx_options.gui_mode_reports && ccx_options.input_source==CCX_DS_NETWORK) {net_activity_gui++; if (!(net_activity_gui%1000))activity_report_data_read();}}
|
||||
|
||||
#define buffered_read_4(buffer) if (4<=bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { buffer[0]=filebuffer[filebuffer_pos]; \
|
||||
buffer[1]=filebuffer[filebuffer_pos+1]; \
|
||||
buffer[2]=filebuffer[filebuffer_pos+2]; \
|
||||
buffer[3]=filebuffer[filebuffer_pos+3]; \
|
||||
filebuffer_pos+=4; \
|
||||
result=4; } \
|
||||
} else result=buffered_read_opt (buffer,4);
|
||||
|
||||
#define buffered_read_byte(buffer) if (bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
|
||||
filebuffer_pos++; \
|
||||
result=1; } \
|
||||
} else result=buffered_read_opt (buffer,1);
|
||||
|
||||
extern LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
// ccextractor.c
|
||||
void init_libraries();
|
||||
|
||||
//params.c
|
||||
void parse_parameters (int argc, char *argv[]);
|
||||
void usage (void);
|
||||
int atoi_hex (char *s);
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt);
|
||||
|
||||
// general_loop.c
|
||||
void position_sanity_check ();
|
||||
int init_file_buffer( void );
|
||||
LLONG ps_getmoredata( void );
|
||||
LLONG general_getmoredata( void );
|
||||
void raw_loop (void *enc_ctx);
|
||||
LLONG process_raw (struct cc_subtitle *sub);
|
||||
void general_loop(void *enc_ctx);
|
||||
void processhex (char *filename);
|
||||
void rcwt_loop(void *enc_ctx);
|
||||
|
||||
// activity.c
|
||||
void activity_header (void);
|
||||
void activity_progress (int percentaje, int cur_min, int cur_sec);
|
||||
void activity_report_version (void);
|
||||
void activity_input_file_closed (void);
|
||||
void activity_input_file_open (const char *filename);
|
||||
void activity_message (const char *fmt, ...);
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate);
|
||||
void activity_program_number (unsigned program_number);
|
||||
void activity_library_process(enum ccx_common_logging_gui message_type, ...);
|
||||
void activity_report_data_read (void);
|
||||
|
||||
extern LLONG result;
|
||||
extern int end_of_file;
|
||||
extern LLONG inbuf;
|
||||
extern int ccx_bufferdatatype; // Can be RAW or PES
|
||||
|
||||
// asf_functions.c
|
||||
LLONG asf_getmoredata( void );
|
||||
|
||||
// wtv_functions.c
|
||||
LLONG wtv_getmoredata( void );
|
||||
|
||||
// avc_functions.c
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen, struct cc_subtitle *sub);
|
||||
void init_avc(void);
|
||||
|
||||
// es_functions.c
|
||||
LLONG process_m2v (unsigned char *data, LLONG length, struct cc_subtitle *sub);
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
// es_userdata.c
|
||||
int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
|
||||
|
||||
// bitstream.c - see bitstream.h
|
||||
|
||||
// file_functions.c
|
||||
LLONG getfilesize (int in);
|
||||
LLONG gettotalfilessize (void);
|
||||
void prepare_for_new_file (void);
|
||||
void close_input_file (void);
|
||||
int switch_to_next_file (LLONG bytesinbuffer);
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
// sequencing.c
|
||||
void init_hdcc (void);
|
||||
void store_hdcc(unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts, struct cc_subtitle *sub);
|
||||
void anchor_hdcc(int seq);
|
||||
void process_hdcc (struct cc_subtitle *sub);
|
||||
int do_cb (unsigned char *cc_block, struct cc_subtitle *sub);
|
||||
// mp4.c
|
||||
int processmp4 (char *file,void *enc_ctx);
|
||||
|
||||
// params_dump.c
|
||||
void params_dump(void);
|
||||
void print_file_report(void);
|
||||
|
||||
// output.c
|
||||
void init_write (struct ccx_s_write *wb);
|
||||
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
|
||||
void writedata(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
void flushbuffer (struct ccx_s_write *wb, int closefile);
|
||||
void printdata (const unsigned char *data1, int length1,const unsigned char *data2, int length2, struct cc_subtitle *sub);
|
||||
void writercwtdata (const unsigned char *data);
|
||||
|
||||
// stream_functions.c
|
||||
void detect_stream_type (void);
|
||||
int detect_myth( void );
|
||||
int read_video_pes_header (unsigned char *header, int *headerlength, int sbuflen);
|
||||
int read_pts_pes(unsigned char*header, int len);
|
||||
|
||||
// ts_functions.c
|
||||
void init_ts( void );
|
||||
int ts_readpacket(void);
|
||||
long ts_readstream(void);
|
||||
LLONG ts_getmoredata( void );
|
||||
int write_section(struct ts_payload *payload, unsigned char*buf, int size, int pos);
|
||||
int parse_PMT (unsigned char *buf,int len, int pos);
|
||||
int parse_PAT (void);
|
||||
|
||||
// myth.c
|
||||
void myth_loop(void *enc_ctx);
|
||||
|
||||
// utility.c
|
||||
void fatal(int exit_code, const char *fmt, ...);
|
||||
void dvprint(const char *fmt, ...);
|
||||
void mprint (const char *fmt, ...);
|
||||
void dbg_print(LLONG mask, const char *fmt, ...);
|
||||
void init_boundary_time (struct ccx_boundary_time *bt);
|
||||
void sleep_secs (int secs);
|
||||
void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, unsigned clear_high_bit);
|
||||
bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) ;
|
||||
int hex2int (char high, char low);
|
||||
void timestamp_to_srttime(uint64_t timestamp, char *buffer);
|
||||
void millis_to_date (uint64_t timestamp, char *buffer) ;
|
||||
int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len);
|
||||
|
||||
|
||||
unsigned encode_line (unsigned char *buffer, unsigned char *text);
|
||||
void buffered_seek (int offset);
|
||||
extern void build_parity_table(void);
|
||||
|
||||
void tlt_process_pes_packet(uint8_t *buffer, uint16_t size) ;
|
||||
void telxcc_init(void);
|
||||
void telxcc_close(void);
|
||||
void tlt_read_rcwt();
|
||||
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,
|
||||
unsigned *seconds, unsigned *ms);
|
||||
|
||||
extern unsigned rollover_bits;
|
||||
extern uint32_t global_timestamp, min_global_timestamp;
|
||||
extern int global_timestamp_inited;
|
||||
|
||||
extern int saw_caption_block;
|
||||
|
||||
|
||||
extern unsigned char *buffer;
|
||||
extern LLONG past;
|
||||
extern LLONG total_inputsize, total_past; // Only in binary concat mode
|
||||
|
||||
extern char **inputfile;
|
||||
extern int current_file;
|
||||
extern LLONG result; // Number of bytes read/skipped in last read operation
|
||||
|
||||
|
||||
extern int strangeheader;
|
||||
|
||||
extern unsigned char startbytes[STARTBYTESLENGTH];
|
||||
extern unsigned int startbytes_pos;
|
||||
extern int startbytes_avail; // Needs to be able to hold -1 result.
|
||||
|
||||
extern unsigned char *pesheaderbuf;
|
||||
|
||||
extern unsigned total_pulldownfields;
|
||||
extern unsigned total_pulldownframes;
|
||||
|
||||
extern unsigned char *filebuffer;
|
||||
extern LLONG filebuffer_start; // Position of buffer start relative to file
|
||||
extern int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
extern int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
|
||||
extern ccx_decoder_608_context context_cc608_field_1, context_cc608_field_2;
|
||||
|
||||
extern const char *desc[256];
|
||||
|
||||
extern FILE *fh_out_elementarystream;
|
||||
extern int infd;
|
||||
extern int false_pict_header;
|
||||
|
||||
extern int stat_numuserheaders;
|
||||
extern int stat_dvdccheaders;
|
||||
extern int stat_scte20ccheaders;
|
||||
extern int stat_replay5000headers;
|
||||
extern int stat_replay4000headers;
|
||||
extern int stat_dishheaders;
|
||||
extern int stat_hdtv;
|
||||
extern int stat_divicom;
|
||||
extern enum ccx_stream_mode_enum stream_mode;
|
||||
extern int cc_stats[4];
|
||||
extern LLONG inputsize;
|
||||
|
||||
extern LLONG subs_delay;
|
||||
extern int startcredits_displayed, end_credits_displayed;
|
||||
extern LLONG last_displayed_subs_ms;
|
||||
extern int processed_enough;
|
||||
|
||||
extern const char *extension;
|
||||
extern long FILEBUFFERSIZE; // Uppercase because it used to be a define
|
||||
extern struct ccx_s_options ccx_options;
|
||||
extern int temp_debug;
|
||||
extern unsigned long net_activity_gui;
|
||||
|
||||
/* General (ES stream) video information */
|
||||
extern unsigned current_hor_size;
|
||||
extern unsigned current_vert_size;
|
||||
extern unsigned current_aspect_ratio;
|
||||
extern unsigned current_frame_rate;
|
||||
|
||||
extern int end_of_file;
|
||||
extern LLONG inbuf;
|
||||
extern enum ccx_bufferdata_type bufferdatatype; // Can be CCX_BUFFERDATA_TYPE_RAW or CCX_BUFFERDATA_TYPE_PES
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
extern int firstcall;
|
||||
|
||||
#define MAXBFRAMES 50
|
||||
#define SORTBUF (2*MAXBFRAMES+1)
|
||||
extern int cc_data_count[SORTBUF];
|
||||
extern unsigned char cc_data_pkts[SORTBUF][10*31*3+1];
|
||||
extern int has_ccdata_buffered;
|
||||
|
||||
extern int last_reported_progress;
|
||||
extern int cc_to_stdout;
|
||||
|
||||
extern unsigned hauppauge_warning_shown;
|
||||
extern unsigned char *subline;
|
||||
extern int saw_gop_header;
|
||||
extern int max_gop_length;
|
||||
extern int last_gop_length;
|
||||
extern int frames_since_last_gop;
|
||||
extern enum ccx_stream_mode_enum auto_stream;
|
||||
extern int num_input_files;
|
||||
extern char *basefilename;
|
||||
extern struct ccx_s_write wbout1, wbout2, *wbxdsout;
|
||||
|
||||
extern int cc608_parity_table[256]; // From myth
|
||||
|
||||
// From ts_functions
|
||||
extern unsigned cap_stream_type;
|
||||
extern struct ts_payload payload;
|
||||
extern unsigned char tspacket[188];
|
||||
extern struct PAT_entry pmt_array[TS_PMT_MAP_SIZE];
|
||||
extern uint16_t pmt_array_length;
|
||||
extern unsigned pmtpid;
|
||||
extern unsigned TS_program_number;
|
||||
extern unsigned char *last_pat_payload;
|
||||
extern unsigned last_pat_length;
|
||||
extern long capbuflen;
|
||||
|
||||
|
||||
#define HAUPPAGE_CCPID 1003 // PID for CC's in some Hauppauge recordings
|
||||
|
||||
/* Exit codes. Take this seriously as the GUI depends on them.
|
||||
0 means OK as usual,
|
||||
<100 means display whatever was output to stderr as a warning
|
||||
>=100 means display whatever was output to stdout as an error
|
||||
*/
|
||||
// Some moved to ccx_common_common.h
|
||||
#define EXIT_OK 0
|
||||
#define EXIT_NO_INPUT_FILES 2
|
||||
#define EXIT_TOO_MANY_INPUT_FILES 3
|
||||
#define EXIT_INCOMPATIBLE_PARAMETERS 4
|
||||
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
|
||||
#define EXIT_MALFORMED_PARAMETER 7
|
||||
#define EXIT_READ_ERROR 8
|
||||
#define EXIT_NOT_CLASSIFIED 300
|
||||
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
|
||||
#define EXIT_BUFFER_FULL 502
|
||||
#define EXIT_MISSING_ASF_HEADER 1001
|
||||
#define EXIT_MISSING_RCWT_HEADER 1002
|
||||
|
||||
extern int PIDs_seen[65536];
|
||||
extern struct PMT_entry *PIDs_programs[65536];
|
||||
|
||||
// extern LLONG ts_start_of_xds; // Moved to 608.h, only referenced in 608.c & xds.c
|
||||
//extern int timestamps_on_transcript;
|
||||
|
||||
extern unsigned teletext_mode;
|
||||
|
||||
#define MAX_TLT_PAGES 1000
|
||||
extern short int seen_sub_page[MAX_TLT_PAGES];
|
||||
|
||||
extern struct ccx_s_teletext_config tlt_config;
|
||||
extern uint32_t tlt_packet_counter;
|
||||
extern uint32_t tlt_frames_produced;
|
||||
|
||||
#endif
|
||||
@@ -1,100 +0,0 @@
|
||||
/* Functions used by both the 608 and 708 decoders. An effort should be
|
||||
made to reuse, not duplicate, as many functions as possible */
|
||||
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_common_char_encoding.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_timing.h"
|
||||
|
||||
uint64_t utc_refvalue = UINT64_MAX; /* _UI64_MAX means don't use UNIX, 0 = use current system time as reference, +1 use a specific reference */
|
||||
|
||||
// Preencoded strings
|
||||
unsigned char encoded_crlf[16];
|
||||
unsigned int encoded_crlf_length;
|
||||
unsigned char encoded_br[16];
|
||||
unsigned int encoded_br_length;
|
||||
|
||||
void ccx_decoders_common_settings_init(LLONG subs_delay, enum ccx_output_format output_format){
|
||||
ccx_decoders_common_settings.subs_delay = subs_delay;
|
||||
ccx_decoders_common_settings.output_format = output_format;
|
||||
}
|
||||
|
||||
LLONG minimum_fts = 0; // No screen should start before this FTS
|
||||
|
||||
/* This function returns a FTS that is guaranteed to be at least 1 ms later than the end of the previous screen. It shouldn't be needed
|
||||
obviously but it guarantees there's no timing overlap */
|
||||
LLONG get_visible_start (void)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts <= minimum_fts)
|
||||
fts = minimum_fts+1;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible Start time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
|
||||
/* This function returns the current FTS and saves it so it can be used by get_visible_start */
|
||||
LLONG get_visible_end (void)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts>minimum_fts)
|
||||
minimum_fts=fts;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible End time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank)
|
||||
{
|
||||
*last_non_blank = -1;
|
||||
*first_non_blank = -1;
|
||||
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
|
||||
{
|
||||
unsigned char c = line[i];
|
||||
if (c != ' ' && c != 0x89)
|
||||
{
|
||||
if (*first_non_blank == -1)
|
||||
*first_non_blank = i;
|
||||
*last_non_blank = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding)
|
||||
{
|
||||
unsigned char *line = data->characters[line_num];
|
||||
int last_non_blank = -1;
|
||||
int first_non_blank = -1;
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
find_limit_characters(line, &first_non_blank, &last_non_blank);
|
||||
if (!trim_subs)
|
||||
first_non_blank = 0;
|
||||
|
||||
if (first_non_blank == -1)
|
||||
{
|
||||
*buffer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytes = 0;
|
||||
for (int i = first_non_blank; i <= last_non_blank; i++)
|
||||
{
|
||||
char c = line[i];
|
||||
switch (encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
bytes = get_char_in_utf_8(buffer, c);
|
||||
break;
|
||||
case CCX_ENC_LATIN_1:
|
||||
get_char_in_latin_1(buffer, c);
|
||||
bytes = 1;
|
||||
break;
|
||||
case CCX_ENC_UNICODE:
|
||||
get_char_in_unicode(buffer, c);
|
||||
bytes = 2;
|
||||
break;
|
||||
}
|
||||
buffer += bytes;
|
||||
}
|
||||
*buffer = 0;
|
||||
return (unsigned)(buffer - orig); // Return length
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/setup.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_AVILIB
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/network.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/odf_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/tools.h>
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/odf_dev.h>
|
||||
|
||||
#ifndef GPAC_MINIMAL_ODF
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/network.h>
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gpac/isomedia.h>
|
||||
#include "../ccextractor.h"
|
||||
#include "../utility.h"
|
||||
#include "../ccx_encoders_common.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub); // From avc_functions.c
|
||||
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub);
|
||||
void set_fts(void); // From timing.c
|
||||
|
||||
static short bswap16(short v)
|
||||
@@ -26,7 +27,7 @@ static struct {
|
||||
unsigned type[32];
|
||||
}s_nalu_stats;
|
||||
|
||||
static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
|
||||
static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
|
||||
{
|
||||
int status = 0;
|
||||
u32 i;
|
||||
@@ -61,14 +62,14 @@ static int process_avc_sample(u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, s
|
||||
temp_debug=0;
|
||||
|
||||
if (nal_length>0)
|
||||
do_NAL ((unsigned char *) &(s->data[i]) ,nal_length, sub);
|
||||
do_NAL (ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
|
||||
i += nal_length;
|
||||
} // outer for
|
||||
assert(i == s->dataLength);
|
||||
|
||||
return status;
|
||||
}
|
||||
static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count;
|
||||
|
||||
@@ -95,16 +96,16 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track, st
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
|
||||
process_m2v ((unsigned char *) s->data,s->dataLength, sub);
|
||||
process_m2v (ctx, (unsigned char *) s->data,s->dataLength, sub);
|
||||
gf_isom_sample_del(&s);
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
@@ -113,7 +114,7 @@ static int process_xdvb_track(const char* basename, GF_ISOFile* f, u32 track, st
|
||||
return status;
|
||||
}
|
||||
|
||||
static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
|
||||
{
|
||||
u32 timescale, i, sample_count, last_sdi = 0;
|
||||
int status;
|
||||
@@ -154,7 +155,7 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, str
|
||||
last_sdi = sdi;
|
||||
}
|
||||
|
||||
status = process_avc_sample(timescale, c, s, sub);
|
||||
status = process_avc_sample(ctx, timescale, c, s, sub);
|
||||
|
||||
gf_isom_sample_del(&s);
|
||||
|
||||
@@ -165,11 +166,11 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, str
|
||||
}
|
||||
|
||||
int progress = (int) ((i*100) / sample_count);
|
||||
if (last_reported_progress != progress)
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
@@ -197,7 +198,7 @@ static int process_avc_track(const char* basename, GF_ISOFile* f, u32 track, str
|
||||
}
|
||||
|
||||
*/
|
||||
int processmp4 (char *file,void *enc_ctx)
|
||||
int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
|
||||
{
|
||||
GF_ISOFile* f;
|
||||
u32 i, j, track_count, avc_track_count, cc_track_count;
|
||||
@@ -245,7 +246,7 @@ int processmp4 (char *file,void *enc_ctx)
|
||||
{
|
||||
if (cc_track_count && !ccx_options.mp4vidtrack)
|
||||
continue;
|
||||
if(process_xdvb_track(file, f, i + 1, &dec_sub) != 0)
|
||||
if(process_xdvb_track(ctx, file, f, i + 1, &dec_sub) != 0)
|
||||
{
|
||||
mprint("error\n");
|
||||
return -3;
|
||||
@@ -267,11 +268,11 @@ int processmp4 (char *file,void *enc_ctx)
|
||||
for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
|
||||
{
|
||||
GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
|
||||
do_NAL ((unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
|
||||
do_NAL (ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
|
||||
}
|
||||
}
|
||||
|
||||
if(process_avc_track(file, f, i + 1, &dec_sub) != 0)
|
||||
if(process_avc_track(ctx, file, f, i + 1, &dec_sub) != 0)
|
||||
{
|
||||
mprint("error\n");
|
||||
return -3;
|
||||
@@ -349,7 +350,7 @@ int processmp4 (char *file,void *enc_ctx)
|
||||
#endif
|
||||
do
|
||||
{
|
||||
ret = process608((unsigned char*)data, len, &context_cc608_field_1, &dec_sub);
|
||||
ret = process608((unsigned char*)data, len, ctx->dec_ctx->context_cc608_field_1, &dec_sub);
|
||||
len -= ret;
|
||||
data += ret;
|
||||
if(dec_sub.got_output)
|
||||
@@ -365,11 +366,11 @@ int processmp4 (char *file,void *enc_ctx)
|
||||
|
||||
// End of change
|
||||
int progress = (int) ((k*100) / num_samples);
|
||||
if (last_reported_progress != progress)
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
@@ -396,9 +397,9 @@ int processmp4 (char *file,void *enc_ctx)
|
||||
else
|
||||
mprint ("found no dedicated CC track(s).\n");
|
||||
|
||||
file_report.mp4_cc_track_cnt = cc_track_count;
|
||||
ctx->freport.mp4_cc_track_cnt = cc_track_count;
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
print_file_report(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/tools.h>
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
|
||||
#ifndef GPAC_DISABLE_ISOM
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/internal/isomedia_dev.h>
|
||||
#include <gpac/constants.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "../disable_warnings.h"
|
||||
#include "disable_warnings.h"
|
||||
#include <gpac/network.h>
|
||||
|
||||
/* the length of the URL separator ("://" || "|//") */
|
||||
|
||||
204
src/lib_ccx/608_sami.c
Normal file
204
src/lib_ccx/608_sami.c
Normal file
@@ -0,0 +1,204 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
|
||||
void write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
|
||||
{
|
||||
int used;
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
int pos_r=0;
|
||||
int pos_w=0;
|
||||
// Scan for \n in the string and replace it with a 0
|
||||
while (pos_r<len)
|
||||
{
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped[pos_w]=string[pos_r];
|
||||
pos_r++;
|
||||
}
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
unsigned int u = encode_line (el, begin);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
write(context->out->fh, encoded_br, encoded_br_length);
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used=encode_line (context->buffer,(unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)ms_end);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
write(context->out->fh, context->buffer, used);
|
||||
free(el);
|
||||
free(unescaped);
|
||||
}
|
||||
|
||||
|
||||
int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cc_bitmap* rect;
|
||||
LLONG ms_start, ms_end;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start + context->subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = sub->start_time + context->subs_delay;
|
||||
ms_end = sub->end_time - 1;
|
||||
}
|
||||
else if ( context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER) )
|
||||
{
|
||||
ms_start = 1 + context->subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
|
||||
#if ENABLE_OCR
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
char *token = NULL;
|
||||
char *buf = (char*)context->buffer;
|
||||
sprintf(buf,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n"
|
||||
,(unsigned long long)ms_start);
|
||||
write(context->out->fh, buf, strlen(buf));
|
||||
token = strtok(rect[0].ocr_text,"\r\n");
|
||||
while (token)
|
||||
{
|
||||
|
||||
sprintf(buf, "%s", token);
|
||||
token = strtok(NULL,"\r\n");
|
||||
if(token)
|
||||
strcat(buf, "<br>\n");
|
||||
else
|
||||
strcat(buf, "\n");
|
||||
write(context->out->fh, buf, strlen(buf));
|
||||
|
||||
}
|
||||
sprintf(buf,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n"
|
||||
,(unsigned long long)ms_end);
|
||||
write(context->out->fh, buf, strlen(buf));
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
return ret;
|
||||
|
||||
}
|
||||
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context)
|
||||
{
|
||||
int used;
|
||||
LLONG startms, endms;
|
||||
int wrote_something=0;
|
||||
startms = data->start_time;
|
||||
|
||||
startms+=context->subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
endms = data->end_time;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
|
||||
(unsigned long long)startms);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s\n",subline);
|
||||
}
|
||||
write (context->out->fh, subline, length);
|
||||
wrote_something=1;
|
||||
if (i!=14)
|
||||
write (context->out->fh, encoded_br, encoded_br_length);
|
||||
write (context->out->fh,encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
sprintf ((char *) str,"</P></SYNC>\r\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,
|
||||
"<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n",
|
||||
(unsigned long long)endms);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
return wrote_something;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
@@ -6,7 +7,7 @@
|
||||
#include "utility.h"
|
||||
|
||||
// Produces minimally-compliant SMPTE Timed Text (W3C TTML)
|
||||
// format-compatible output
|
||||
// format-compatible output
|
||||
|
||||
// See http://www.w3.org/TR/ttaf1-dfxp/ and
|
||||
// https://www.smpte.org/sites/default/files/st2052-1-2010.pdf
|
||||
@@ -36,7 +37,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2);
|
||||
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
@@ -44,7 +45,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
int len=strlen (string);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *unescaped= (unsigned char *) malloc (len+1);
|
||||
unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
|
||||
if (el==NULL || unescaped==NULL)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
|
||||
@@ -56,7 +57,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
if (string[pos_r]=='\\' && string[pos_r+1]=='n')
|
||||
{
|
||||
unescaped[pos_w]=0;
|
||||
pos_r+=2;
|
||||
pos_r+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -66,7 +67,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
pos_w++;
|
||||
}
|
||||
unescaped[pos_w]=0;
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
// Now read the unescaped string (now several string'z and write them)
|
||||
unsigned char *begin=unescaped;
|
||||
while (begin<unescaped+len)
|
||||
{
|
||||
@@ -78,7 +79,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
}
|
||||
write(context->out->fh, el, u);
|
||||
//write (wb->fh, encoded_br, encoded_br_length);
|
||||
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
begin+= strlen ((const char *) begin)+1;
|
||||
}
|
||||
@@ -90,7 +91,7 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
}
|
||||
used = encode_line(context->buffer,(unsigned char *) str);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\">\n\n",h2,m2,s2,ms2);
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u.%03u\">\n\n",h2,m2,s2,ms2);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
@@ -105,135 +106,60 @@ void write_stringz_as_smptett(char *string, struct encoder_ctx *context, LLONG m
|
||||
|
||||
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
//char *filename;
|
||||
int ret = 0;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
//int used;
|
||||
#ifdef ENABLE_OCR
|
||||
unsigned h1, m1, s1, ms1;
|
||||
unsigned h2, m2, s2, ms2;
|
||||
#endif
|
||||
LLONG ms_start, ms_end;
|
||||
//char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start + subs_delay;
|
||||
ms_start = context->prev_start + context->subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = sub->start_time + subs_delay;
|
||||
ms_start = sub->start_time + context->subs_delay;
|
||||
ms_end = sub->end_time - 1;
|
||||
}
|
||||
else if (context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = 1 + context->subs_delay;
|
||||
ms_end = sub->start_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
char *buf = (char *) context->buffer;
|
||||
unsigned h1, m1, s1, ms1;
|
||||
unsigned h2, m2, s2, ms2;
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
sprintf ((char *) context->buffer,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u,%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
write (context->out->fh, context->buffer,strlen(context->buffer) );
|
||||
len = strlen(str);
|
||||
write (context->out->fh, str, len);
|
||||
sprintf ((char *) context->buffer,"<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
write (context->out->fh, buf,strlen(buf) );
|
||||
len = strlen(rect[0].ocr_text);
|
||||
write (context->out->fh, rect[0].ocr_text, len);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
sprintf ((char *) str,"</p>\n");
|
||||
sprintf ( buf,"</p>\n");
|
||||
write (context->out->fh, buf,strlen(buf) );
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
@@ -247,16 +173,16 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
|
||||
int wrote_something=0;
|
||||
LLONG startms = data->start_time;
|
||||
|
||||
startms+=subs_delay;
|
||||
startms+=context->subs_delay;
|
||||
if (startms<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
endms = data->end_time;
|
||||
endms--; // To prevent overlapping with next line.
|
||||
mstotime (startms,&h1,&m1,&s1,&ms1);
|
||||
mstotime (endms-1,&h2,&m2,&s2,&ms2);
|
||||
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u,%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u.%03u\" end=\"%02u:%02u:%02u.%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
@@ -267,7 +193,7 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
|
||||
for (int i=0;i<15;i++)
|
||||
{
|
||||
if (data->row_used[i])
|
||||
{
|
||||
{
|
||||
int length = get_decoder_line_encoded (subline, i, data);
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
@@ -276,7 +202,7 @@ int write_cc_buffer_as_smptett(struct eia608_screen *data, struct encoder_ctx *c
|
||||
}
|
||||
write(context->out->fh, subline, length);
|
||||
wrote_something=1;
|
||||
|
||||
|
||||
write(context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ spupng_write_png(struct spupng_t *sp, struct eia608_screen* data,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
@@ -124,7 +124,7 @@ spupng_export_png(struct spupng_t *sp, struct eia608_screen* data)
|
||||
png_bytep *row_pointer;
|
||||
png_bytep image;
|
||||
int ww, wh, rowstride, row_adv;
|
||||
int row;
|
||||
int row;
|
||||
|
||||
assert ((sizeof(png_byte) == sizeof(uint8_t))
|
||||
&& (sizeof(*image) == sizeof(uint8_t)));
|
||||
@@ -196,7 +196,7 @@ int
|
||||
spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
struct encoder_ctx *context)
|
||||
{
|
||||
LLONG ms_start = data->start_time + subs_delay;
|
||||
LLONG ms_start = data->start_time + context->subs_delay;
|
||||
if (ms_start < 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Negative start\n");
|
||||
@@ -263,7 +263,7 @@ spupng_write_ccbuffer(struct spupng_t *sp, struct eia608_screen* data,
|
||||
strncat(str,"\n",256);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
write_spucomment(sp,str);
|
||||
return 1;
|
||||
}
|
||||
@@ -276,4 +276,3 @@ int write_cc_buffer_as_spupng(struct eia608_screen *data,struct encoder_ctx *con
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifndef __608_SPUPNG_H__
|
||||
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "png.h"
|
||||
#include "spupng_encoder.h"
|
||||
#include "ocr.h"
|
||||
#include "utility.h"
|
||||
|
||||
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
|
||||
@@ -17,11 +15,11 @@ void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_st
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
sprintf(timeline, "%u%s", context->srt_counter, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption - - -\n");
|
||||
dbg_print(CCX_DMT_DECODER_608, "%s",timeline);
|
||||
@@ -74,17 +72,8 @@ void write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_st
|
||||
|
||||
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
//char *filename;
|
||||
int ret = 0;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
LLONG ms_start, ms_end;
|
||||
#ifdef ENABLE_OCR
|
||||
unsigned h1,m1,s1,ms1;
|
||||
@@ -94,11 +83,6 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
int used;
|
||||
#endif
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = context->prev_start;
|
||||
@@ -109,79 +93,21 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
ms_start = sub->start_time;
|
||||
ms_end = sub->end_time;
|
||||
}
|
||||
else if (context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
ms_start = 1;
|
||||
ms_end = sub->start_time;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
if(sub->flags & SUB_EOD_MARKER)
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
rect = sub->data;
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
@@ -195,18 +121,14 @@ int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write (context->out->fh, context->buffer, used);
|
||||
len = strlen(str);
|
||||
write (context->out->fh, str, len);
|
||||
len = strlen(rect[0].ocr_text);
|
||||
write (context->out->fh, rect[0].ocr_text, len);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
@@ -233,7 +155,7 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
if (empty_buf) // Prevent writing empty screens. Not needed in .srt
|
||||
return 0;
|
||||
|
||||
ms_start+=subs_delay;
|
||||
ms_start+=context->subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return 0;
|
||||
|
||||
@@ -243,11 +165,11 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
context->srt_counter++;
|
||||
sprintf(timeline, "%u\r\n", context->srt_counter);
|
||||
sprintf(timeline, "%u%s", context->srt_counter, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
write(context->out->fh, context->buffer, used);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
|
||||
h1, m1, s1, ms1, h2, m2, s2, ms2, encoded_crlf);
|
||||
used = encode_line(context->buffer,(unsigned char *) timeline);
|
||||
|
||||
dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
|
||||
@@ -335,6 +257,6 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *conte
|
||||
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
|
||||
|
||||
// fprintf (wb->fh, encoded_crlf);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
write (context->out->fh, encoded_crlf, encoded_crlf_length);
|
||||
return wrote_something;
|
||||
}
|
||||
@@ -4,10 +4,10 @@ EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE)
|
||||
|
||||
00-1F -> Characters that are in the G2 group in 20-3F,
|
||||
except for 06, which is used for the closed captions
|
||||
sign "CC" which is defined in group G3 as 00. (this
|
||||
sign "CC" which is defined in group G3 as 00. (this
|
||||
is by the article 33).
|
||||
20-7F -> Group G0 as is - corresponds to the ASCII code
|
||||
80-9F -> Characters that are in the G2 group in 60-7F
|
||||
20-7F -> Group G0 as is - corresponds to the ASCII code
|
||||
80-9F -> Characters that are in the G2 group in 60-7F
|
||||
(there are several blank characters here, that's OK)
|
||||
A0-FF -> Group G1 as is - non-English characters and symbols
|
||||
*/
|
||||
@@ -31,7 +31,7 @@ unsigned char get_internal_from_G2 (unsigned char g2_char)
|
||||
if (g2_char>=0x60 && g2_char<=0x7F)
|
||||
return g2_char+0x20;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
// TODO: Probably not right
|
||||
@@ -39,7 +39,7 @@ unsigned char get_internal_from_G2 (unsigned char g2_char)
|
||||
unsigned char get_internal_from_G3 (unsigned char g3_char)
|
||||
{
|
||||
if (g3_char==0xa0) // The "CC" (closed captions) sign
|
||||
return 0x06;
|
||||
return 0x06;
|
||||
// Rest unmapped, so we return a blank space
|
||||
return 0x20;
|
||||
return 0x20;
|
||||
}
|
||||
27
src/lib_ccx/CMakeLists.txt
Normal file
27
src/lib_ccx/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
cmake_policy(SET CMP0037 NEW)
|
||||
|
||||
SET (CMAKE_C_FLAGS "-O0 -Wall -g -std=gnu99")
|
||||
|
||||
if (WITH_FFMPEG)
|
||||
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
|
||||
endif (WITH_FFMPEG)
|
||||
|
||||
AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE)
|
||||
AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/gpacmp4/" SOURCEFILE)
|
||||
#AUX_SOURCE_DIRECTORY("${PROJECT_SOURCE_DIR}/libpng/" SOURCEFILE)
|
||||
add_library(ccx ${SOURCEFILE})
|
||||
|
||||
FILE(GLOB HeaderFiles *.h)
|
||||
file(WRITE ccx.pc "prefix=${CMAKE_INSTALL_PREFIX}\n"
|
||||
"includedir=\${prefix}/include\n"
|
||||
"libdir=\${prefix}/lib\n\n"
|
||||
"Name: ccx\n"
|
||||
"Description: Closed Caption Extraction library\n"
|
||||
"Version: 0.75\n"
|
||||
"Cflags: -I\${includedir}/\n"
|
||||
"Libs: -L\${libdir} -lccx -lpng\n"
|
||||
"Libs.private: -lpng\n" )
|
||||
|
||||
install (TARGETS ccx DESTINATION lib)
|
||||
install (FILES ${HeaderFiles} DESTINATION include)
|
||||
install (FILES ccx.pc DESTINATION lib/pkgconfig )
|
||||
@@ -1,7 +1,8 @@
|
||||
/* This file contains functions that report the user of the GUI of
|
||||
relevant events. */
|
||||
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
static int credits_shown=0;
|
||||
unsigned long net_activity_gui=0;
|
||||
@@ -29,7 +30,7 @@ void activity_input_file_open (const char *filename)
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###INPUTFILEOPEN#%s\n", filename);
|
||||
fflush (stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,29 +60,29 @@ void activity_library_process(enum ccx_common_logging_gui message_type, ...){
|
||||
}
|
||||
}
|
||||
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###VIDEOINFO#%u#%u#%s#%s\n",
|
||||
hor_size,vert_size, aspect_ratio, framerate);
|
||||
fflush (stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void activity_message (const char *fmt, ...)
|
||||
{
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
va_list args;
|
||||
va_list args;
|
||||
fprintf (stderr, "###MESSAGE#");
|
||||
va_start(args, fmt);
|
||||
fprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
fflush (stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ void activity_input_file_closed (void)
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###INPUTFILECLOSED\n");
|
||||
fflush (stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +100,7 @@ void activity_program_number (unsigned program_number)
|
||||
if (ccx_options.gui_mode_reports)
|
||||
{
|
||||
fprintf (stderr, "###TSPROGRAMNUMBER#%u\n",program_number);
|
||||
fflush (stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +130,6 @@ void activity_header (void)
|
||||
credits_shown=1;
|
||||
mprint ("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION);
|
||||
mprint ("Teletext portions taken from Petr Kutalek's telxcc\n");
|
||||
mprint ("--------------------------------------------------------------------------\n");
|
||||
mprint ("--------------------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "asf_constants.h"
|
||||
|
||||
// Indicate first / subsequent calls to asf_getmoredata()
|
||||
@@ -28,7 +29,7 @@ uint32_t asf_readval(void *val, int ltype)
|
||||
rval = *((uint32_t*)val);
|
||||
break;
|
||||
default:
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
|
||||
break;
|
||||
}
|
||||
return rval;
|
||||
@@ -60,7 +61,7 @@ asf_data asf_data_container;
|
||||
* When the function is called the next time it continues to read
|
||||
* where it stopped before, static variables make sure that parameters
|
||||
* are remembered between calls. */
|
||||
LLONG asf_getmoredata(void)
|
||||
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int enough = 0;
|
||||
int payload_read = 0;
|
||||
@@ -81,14 +82,14 @@ LLONG asf_getmoredata(void)
|
||||
// Data Object Loop
|
||||
int datapacketlength = 0; // Collect the read header bytes
|
||||
|
||||
// Payload parsing information
|
||||
// Payload parsing information
|
||||
int SequenceType = 0; // ASF
|
||||
int PaddingLType = 0; // ASF
|
||||
uint32_t Sequence = 0;
|
||||
int PaddingLType = 0; // ASF
|
||||
uint32_t Sequence = 0;
|
||||
uint32_t SendTime = 0;
|
||||
|
||||
int payloadparsersize = 0; // Infered (PacketLType + SequenceType + PaddingLType + 6);
|
||||
|
||||
|
||||
uint32_t OffsetMediaLength = 0; // ASF
|
||||
uint32_t ReplicatedLength = 0; // ASF
|
||||
|
||||
@@ -140,7 +141,7 @@ LLONG asf_getmoredata(void)
|
||||
.StreamNumberLType = 0,
|
||||
.PacketLength = 0,
|
||||
.PaddingLength = 0
|
||||
};
|
||||
};
|
||||
// Initialize the Payload Extension System
|
||||
for(int stream=0; stream<STREAMNUM; stream++)
|
||||
{
|
||||
@@ -151,8 +152,8 @@ LLONG asf_getmoredata(void)
|
||||
asf_data_container.PayloadExtPTSEntry[stream] = -1;
|
||||
}
|
||||
|
||||
buffered_read(asf_data_container.parsebuf,30);
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf,30);
|
||||
ctx->past+=result;
|
||||
if (result!=30)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -173,7 +174,7 @@ LLONG asf_getmoredata(void)
|
||||
dbg_print(CCX_DMT_PARSE, "Length: %lld\n", asf_data_container.HeaderObjectSize);
|
||||
dbg_print(CCX_DMT_PARSE,"\nNumber of header objects: %ld\n",
|
||||
(long)*((uint32_t*)(asf_data_container.parsebuf + 24)));
|
||||
|
||||
|
||||
|
||||
if (asf_data_container.HeaderObjectSize > asf_data_container.parsebufsize) {
|
||||
asf_data_container.parsebuf = (unsigned char*)realloc(asf_data_container.parsebuf, (size_t)asf_data_container.HeaderObjectSize);
|
||||
@@ -185,8 +186,8 @@ LLONG asf_getmoredata(void)
|
||||
curpos = asf_data_container.parsebuf + 30;
|
||||
getbytes = asf_data_container.HeaderObjectSize - 30;
|
||||
|
||||
buffered_read(curpos, (int) getbytes);
|
||||
past+=result;
|
||||
buffered_read(ctx, curpos, (int) getbytes);
|
||||
ctx->past+=result;
|
||||
if (result!=getbytes)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -202,7 +203,7 @@ LLONG asf_getmoredata(void)
|
||||
|
||||
if( !memcmp(curpos, ASF_FILE_PROPERTIES, 16 ) )
|
||||
{
|
||||
// Mandatory Object, only one.
|
||||
// Mandatory Object, only one.
|
||||
dbg_print(CCX_DMT_PARSE, "\nFile Properties Object (size: %lld)\n", hpobjectsize);
|
||||
|
||||
asf_data_container.FileSize = *((int64_t*)(curpos + 40));
|
||||
@@ -211,11 +212,11 @@ LLONG asf_getmoredata(void)
|
||||
SeekableFlag = 0x2 & curpos[88];
|
||||
MinPacketSize = *((uint32_t*)(curpos+92));
|
||||
MaxPacketSize = *((uint32_t*)(curpos+96));
|
||||
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "FileSize: %lld Packet count: %lld\n", asf_data_container.FileSize, DataPacketsCount);
|
||||
dbg_print(CCX_DMT_PARSE, "Broadcast: %d - Seekable: %d\n", BroadcastFlag, SeekableFlag);
|
||||
dbg_print(CCX_DMT_PARSE, "MiDPS: %d MaDPS: %d\n", MinPacketSize, MaxPacketSize);
|
||||
|
||||
|
||||
}
|
||||
else if( !memcmp(curpos,ASF_STREAM_PROPERTIES, 16 ) )
|
||||
{
|
||||
@@ -225,7 +226,7 @@ LLONG asf_getmoredata(void)
|
||||
asf_data_container.StreamProperties.VideoStreamNumber = *(curpos + 72) & 0x7F;
|
||||
dbg_print(CCX_DMT_PARSE, "Stream Type: ASF_Video_Media\n");
|
||||
dbg_print(CCX_DMT_PARSE, "Video Stream Number: %d\n", asf_data_container.StreamProperties.VideoStreamNumber);
|
||||
|
||||
|
||||
}
|
||||
else if( !memcmp(curpos+24, ASF_AUDIO_MEDIA, 16 ) )
|
||||
{
|
||||
@@ -237,7 +238,7 @@ LLONG asf_getmoredata(void)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "Stream Type: %s\n",
|
||||
guidstr(curpos+24));
|
||||
dbg_print(CCX_DMT_PARSE, "Stream Number: %d\n", *(curpos+72) & 0x7F );
|
||||
dbg_print(CCX_DMT_PARSE, "Stream Number: %d\n", *(curpos+72) & 0x7F );
|
||||
}
|
||||
}
|
||||
else if( !memcmp(curpos,ASF_HEADER_EXTENSION, 16 ) )
|
||||
@@ -439,7 +440,7 @@ LLONG asf_getmoredata(void)
|
||||
dbg_print(CCX_DMT_PARSE, "%02X:",*((unsigned char*)(edescval+ii)));
|
||||
}
|
||||
if (DescriptorValueLength>8)
|
||||
dbg_print(CCX_DMT_PARSE, "skipped %d more",DescriptorValueLength-8);
|
||||
dbg_print(CCX_DMT_PARSE, "skipped %d more",DescriptorValueLength-8);
|
||||
dbg_print(CCX_DMT_PARSE, " (BYTES)\n");
|
||||
break;
|
||||
case 2: // BOOL
|
||||
@@ -458,7 +459,7 @@ LLONG asf_getmoredata(void)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Wrong type ...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(!memcmp(econtentpos+2, L"WM/VideoClosedCaptioning"
|
||||
,DescriptorNameLength))
|
||||
{
|
||||
@@ -534,8 +535,8 @@ LLONG asf_getmoredata(void)
|
||||
asf_data_container.PacketSize = MinPacketSize;
|
||||
|
||||
// Now the Data Object, except for the packages
|
||||
buffered_read(asf_data_container.parsebuf, 50); // No realloc needed.
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf, 50); // No realloc needed.
|
||||
ctx->past+=result;
|
||||
if (result!=50)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -557,7 +558,7 @@ LLONG asf_getmoredata(void)
|
||||
asf_data_container.TotalDataPackets = *((uint32_t*)(asf_data_container.parsebuf + 40));
|
||||
dbg_print(CCX_DMT_PARSE, "Size: %lld\n", asf_data_container.DataObjectSize);
|
||||
dbg_print(CCX_DMT_PARSE, "Number of data packets: %ld\n", (long)asf_data_container.TotalDataPackets);
|
||||
|
||||
|
||||
|
||||
reentry = 0; // Make sure we read the Data Packet Headers
|
||||
} // End of if (firstcall)
|
||||
@@ -576,8 +577,8 @@ LLONG asf_getmoredata(void)
|
||||
dbg_print(CCX_DMT_PARSE, "\nReading packet %d/%d\n", asf_data_container.datapacketcur + 1, asf_data_container.TotalDataPackets);
|
||||
|
||||
// First packet
|
||||
buffered_read(asf_data_container.parsebuf, 1); // No realloc needed.
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf, 1); // No realloc needed.
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=1)
|
||||
{
|
||||
@@ -593,8 +594,8 @@ LLONG asf_getmoredata(void)
|
||||
{
|
||||
fatal(EXIT_NOT_CLASSIFIED, "Error Correction Length Type not 00 - reserved - aborting ...\n");
|
||||
}
|
||||
buffered_read(asf_data_container.parsebuf + 1, ecdatalength);
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf + 1, ecdatalength);
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=ecdatalength)
|
||||
{
|
||||
@@ -614,8 +615,8 @@ LLONG asf_getmoredata(void)
|
||||
}
|
||||
|
||||
// Now payload parsing information
|
||||
buffered_read(asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf + ecinfo, 2 - ecinfo); // No realloc needed
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=2)
|
||||
{
|
||||
@@ -650,8 +651,8 @@ LLONG asf_getmoredata(void)
|
||||
|
||||
payloadparsersize = asf_data_container.PacketLType + SequenceType + PaddingLType + 6;
|
||||
|
||||
buffered_read(asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf + 2, payloadparsersize); // No realloc needed
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=payloadparsersize)
|
||||
{
|
||||
@@ -688,8 +689,8 @@ LLONG asf_getmoredata(void)
|
||||
{
|
||||
unsigned char plheader[1];
|
||||
|
||||
buffered_read(plheader, 1);
|
||||
past+=result;
|
||||
buffered_read(ctx, plheader, 1);
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=1)
|
||||
{
|
||||
@@ -726,9 +727,9 @@ LLONG asf_getmoredata(void)
|
||||
dbg_print(CCX_DMT_PARSE, "\nMultiple payloads %d/%d\n", asf_data_container.payloadcur + 1, asf_data_container.NumberOfPayloads);
|
||||
|
||||
int payloadheadersize = 1 + asf_data_container.MediaNumberLType + asf_data_container.OffsetMediaLType + asf_data_container.ReplicatedLType;
|
||||
|
||||
buffered_read(asf_data_container.parsebuf, payloadheadersize); // No realloc needed
|
||||
past+=result;
|
||||
|
||||
buffered_read(ctx, asf_data_container.parsebuf, payloadheadersize); // No realloc needed
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=payloadheadersize)
|
||||
{
|
||||
@@ -737,7 +738,7 @@ LLONG asf_getmoredata(void)
|
||||
return payload_read;
|
||||
}
|
||||
datapacketlength+=payloadheadersize;
|
||||
|
||||
|
||||
asf_data_container.PayloadStreamNumber = *asf_data_container.parsebuf & 0x7F;
|
||||
asf_data_container.KeyFrame = (*asf_data_container.parsebuf & 0x80) && 1;
|
||||
|
||||
@@ -755,8 +756,8 @@ LLONG asf_getmoredata(void)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
asf_data_container.parsebufsize = ReplicatedLength;
|
||||
}
|
||||
buffered_read(asf_data_container.parsebuf, (long)ReplicatedLength);
|
||||
past+=result;
|
||||
buffered_read(ctx, asf_data_container.parsebuf, (long)ReplicatedLength);
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result!=ReplicatedLength)
|
||||
{
|
||||
@@ -804,7 +805,7 @@ LLONG asf_getmoredata(void)
|
||||
// unknown = *((uint32_t*)(reppos+4));
|
||||
rtStart = *((int64_t*)(reppos+8));
|
||||
rtEnd = *((int64_t*)(reppos+16));
|
||||
|
||||
|
||||
//printf("dwVersion: %d unknown: 0x%04X\n", dwVersion, unknown);
|
||||
}
|
||||
|
||||
@@ -823,7 +824,7 @@ LLONG asf_getmoredata(void)
|
||||
print_mstime(PresentationTimems));
|
||||
dbg_print(CCX_DMT_PARSE," dvr-ms PTS: %s+%lld\n",
|
||||
print_mstime(rtStart/10000), (rtEnd-rtStart)/10000);
|
||||
|
||||
|
||||
datapacketlength+=ReplicatedLength;
|
||||
|
||||
// Only multiple payload packages have this value
|
||||
@@ -831,8 +832,8 @@ LLONG asf_getmoredata(void)
|
||||
{
|
||||
unsigned char plheader[4];
|
||||
|
||||
buffered_read(plheader, asf_data_container.PayloadLType);
|
||||
past+=result;
|
||||
buffered_read(ctx, plheader, asf_data_container.PayloadLType);
|
||||
ctx->past+=result;
|
||||
asf_data_container.dobjectread += result;
|
||||
if (result != asf_data_container.PayloadLType)
|
||||
{
|
||||
@@ -955,7 +956,7 @@ LLONG asf_getmoredata(void)
|
||||
dbg_print(CCX_DMT_PARSE, "\nVideo stream object");
|
||||
dbg_print(CCX_DMT_PARSE, " read with PTS: %s\n",
|
||||
print_mstime(asf_data_container.StreamProperties.currDecodeStreamPTS));
|
||||
|
||||
|
||||
|
||||
// Enough for now
|
||||
enough = 1;
|
||||
@@ -974,10 +975,10 @@ LLONG asf_getmoredata(void)
|
||||
asf_data_container.PayloadLength : (BUFSIZE - inbuf));
|
||||
if (want < (long)asf_data_container.PayloadLength)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Buffer size to small for ASF payload!\nPlease file a bug report!\n");
|
||||
buffered_read (buffer+inbuf,want);
|
||||
buffered_read (ctx, ctx->buffer+inbuf,want);
|
||||
payload_read+=(int) result;
|
||||
inbuf+=result;
|
||||
past+=result;
|
||||
ctx->past+=result;
|
||||
if (result != asf_data_container.PayloadLength)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -990,8 +991,8 @@ LLONG asf_getmoredata(void)
|
||||
{
|
||||
// Skip non-cc data
|
||||
dbg_print(CCX_DMT_PARSE, "Skipping Stream #%d data ...\n", asf_data_container.PayloadStreamNumber);
|
||||
buffered_skip((int)asf_data_container.PayloadLength);
|
||||
past+=result;
|
||||
buffered_skip(ctx, (int)asf_data_container.PayloadLength);
|
||||
ctx->past+=result;
|
||||
if (result != asf_data_container.PayloadLength)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -1000,7 +1001,7 @@ LLONG asf_getmoredata(void)
|
||||
}
|
||||
asf_data_container.dobjectread += result;
|
||||
}
|
||||
|
||||
|
||||
asf_data_container.payloadcur++;
|
||||
}
|
||||
if (enough)
|
||||
@@ -1008,8 +1009,8 @@ LLONG asf_getmoredata(void)
|
||||
|
||||
// Skip padding bytes
|
||||
dbg_print(CCX_DMT_PARSE, "Skip %d padding\n", asf_data_container.PaddingLength);
|
||||
buffered_skip((long)asf_data_container.PaddingLength);
|
||||
past+=result;
|
||||
buffered_skip(ctx, (long)asf_data_container.PaddingLength);
|
||||
ctx->past+=result;
|
||||
if (result != asf_data_container.PaddingLength)
|
||||
{
|
||||
mprint("Premature end of file!\n");
|
||||
@@ -1028,8 +1029,8 @@ LLONG asf_getmoredata(void)
|
||||
|
||||
// Skip the rest of the file
|
||||
dbg_print(CCX_DMT_PARSE, "Skip the rest: %d\n", (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
|
||||
buffered_skip((int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
|
||||
past+=result;
|
||||
buffered_skip(ctx, (int)(asf_data_container.FileSize - asf_data_container.HeaderObjectSize - asf_data_container.DataObjectSize));
|
||||
ctx->past+=result;
|
||||
// Don not set end_of_file (although it is true) as this would
|
||||
// produce an premature end error.
|
||||
//end_of_file=1;
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "utility.h"
|
||||
#include <math.h>
|
||||
|
||||
// Functions to parse a AVC/H.264 data stream, see ISO/IEC 14496-10
|
||||
// Functions to parse a AVC/H.264 data stream, see ISO/IEC 14496-10
|
||||
|
||||
int ccblocks_in_avc_total=0;
|
||||
int ccblocks_in_avc_lost=0;
|
||||
@@ -12,7 +14,7 @@ static void sei_rbsp (unsigned char *seibuf, unsigned char *seiend);
|
||||
static unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend);
|
||||
static void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *userend);
|
||||
static void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend);
|
||||
static void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
|
||||
static void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub);
|
||||
|
||||
static unsigned char cc_count;
|
||||
// buffer to hold cc data
|
||||
@@ -44,15 +46,15 @@ void init_avc(void)
|
||||
cc_data = (unsigned char*)malloc(1024);
|
||||
}
|
||||
|
||||
void do_NAL (unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
void do_NAL (struct lib_ccx_ctx *ctx, unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char *NALstop;
|
||||
unsigned nal_unit_type = *NALstart & 0x1F;
|
||||
|
||||
NALstop = NAL_length+NALstart;
|
||||
NALstop = NAL_length+NALstart;
|
||||
NALstop = remove_03emu(NALstart+1, NALstop); // Add +1 to NALstop for TS, without it for MP4. Still don't know why
|
||||
|
||||
if (NALstop==NULL) // remove_03emu failed.
|
||||
if (NALstop==NULL) // remove_03emu failed.
|
||||
{
|
||||
mprint ("\rNotice: NAL of type %u had to be skipped because remove_03emu failed.\n", nal_unit_type);
|
||||
return;
|
||||
@@ -66,22 +68,22 @@ void do_NAL (unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
{
|
||||
// Found sequence parameter set
|
||||
// We need this to parse NAL type 1 (CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1)
|
||||
num_nal_unit_type_7++;
|
||||
num_nal_unit_type_7++;
|
||||
seq_parameter_set_rbsp(NALstart+1, NALstop);
|
||||
got_seq_para = 1;
|
||||
}
|
||||
else if ( got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
|
||||
else if ( got_seq_para && (nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_NON_IDR_PICTURE_1 ||
|
||||
nal_unit_type == CCX_NAL_TYPE_CODED_SLICE_IDR_PICTURE)) // Only if nal_unit_type=1
|
||||
{
|
||||
// Found coded slice of a non-IDR picture
|
||||
// Found coded slice of a non-IDR picture
|
||||
// We only need the slice header data, no need to implement
|
||||
// slice_layer_without_partitioning_rbsp( );
|
||||
slice_header(NALstart+1, NALstop, nal_unit_type, sub);
|
||||
slice_header(ctx, NALstart+1, NALstop, nal_unit_type, sub);
|
||||
}
|
||||
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_SEI )
|
||||
{
|
||||
// Found SEI (used for subtitles)
|
||||
//set_fts(); // FIXME - check this!!!
|
||||
//set_fts(); // FIXME - check this!!!
|
||||
sei_rbsp(NALstart+1, NALstop);
|
||||
}
|
||||
else if ( got_seq_para && nal_unit_type == CCX_NAL_TYPE_PICTURE_PARAMETER_SET )
|
||||
@@ -99,7 +101,7 @@ void do_NAL (unsigned char *NALstart, LLONG NAL_length, struct cc_subtitle *sub)
|
||||
|
||||
// Process inbuf bytes in buffer holding and AVC (H.264) video stream.
|
||||
// The number of processed bytes is returned.
|
||||
LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
|
||||
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char *bpos = avcbuf;
|
||||
unsigned char *NALstart;
|
||||
@@ -110,14 +112,14 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *s
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG,
|
||||
"NAL unit need at last 5 bytes ...");
|
||||
}
|
||||
}
|
||||
|
||||
// Warning there should be only leading zeros, nothing else
|
||||
// Warning there should be only leading zeros, nothing else
|
||||
if( !(bpos[0]==0x00 && bpos[1]==0x00) )
|
||||
{
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG,
|
||||
"Broken AVC stream - no 0x0000 ...");
|
||||
}
|
||||
}
|
||||
bpos = bpos+2;
|
||||
|
||||
int firstloop=1; // Check for valid start code at buffer start
|
||||
@@ -202,17 +204,17 @@ LLONG process_avc (unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *s
|
||||
|
||||
dvprint("BEGIN NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions before: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
|
||||
|
||||
do_NAL (NALstart, NALstop-NALstart, sub);
|
||||
|
||||
do_NAL (ctx, NALstart, NALstop-NALstart, sub);
|
||||
|
||||
dvprint("END NAL unit type: %d length %d zeros: %d ref_idc: %d - Buffered captions after: %d\n",
|
||||
nal_unit_type, NALstop-NALstart-1, zeropad, nal_ref_idc, !cc_buffer_saved);
|
||||
}
|
||||
}
|
||||
|
||||
return avcbuflen;
|
||||
}
|
||||
|
||||
#define ZEROBYTES_SHORTSTARTCODE 2
|
||||
#define ZEROBYTES_SHORTSTARTCODE 2
|
||||
|
||||
// Copied for reference decoder, see if it behaves different that Volker's code
|
||||
int EBSPtoRBSP(unsigned char *streamBuffer, int end_bytepos, int begin_bytepos)
|
||||
@@ -227,9 +229,9 @@ int EBSPtoRBSP(unsigned char *streamBuffer, int end_bytepos, int begin_bytepos)
|
||||
|
||||
for(i = begin_bytepos; i < end_bytepos; ++i)
|
||||
{ //starting from begin_bytepos to avoid header information
|
||||
//in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position
|
||||
if(count == ZEROBYTES_SHORTSTARTCODE && streamBuffer[i] < 0x03)
|
||||
return -1;
|
||||
//in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position
|
||||
if(count == ZEROBYTES_SHORTSTARTCODE && streamBuffer[i] < 0x03)
|
||||
return -1;
|
||||
if(count == ZEROBYTES_SHORTSTARTCODE && streamBuffer[i] == 0x03)
|
||||
{
|
||||
//check the 4th byte after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003
|
||||
@@ -260,8 +262,8 @@ typedef unsigned int u32;
|
||||
u32 avc_remove_emulation_bytes(const unsigned char *buffer_src, unsigned char *buffer_dst, u32 nal_size) ;
|
||||
|
||||
unsigned char *remove_03emu(unsigned char *from, unsigned char *to)
|
||||
{
|
||||
int num=to-from;
|
||||
{
|
||||
int num=to-from;
|
||||
int newsize = EBSPtoRBSP (from,num,0); //TODO: Do something if newsize == -1 (broken NAL)
|
||||
if (newsize==-1)
|
||||
return NULL;
|
||||
@@ -282,7 +284,7 @@ void sei_rbsp (unsigned char *seibuf, unsigned char *seiend)
|
||||
{
|
||||
if(*tbuf != 0x80)
|
||||
mprint("Strange rbsp_trailing_bits value: %02X\n",*tbuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This really really looks bad
|
||||
@@ -305,33 +307,33 @@ unsigned char *sei_message (unsigned char *seibuf, unsigned char *seiend)
|
||||
payloadType+=255;
|
||||
seibuf++;
|
||||
}
|
||||
payloadType += *seibuf;
|
||||
payloadType += *seibuf;
|
||||
seibuf++;
|
||||
|
||||
|
||||
|
||||
int payloadSize = 0;
|
||||
while (*seibuf==0xff)
|
||||
{
|
||||
payloadSize+=255;
|
||||
seibuf++;
|
||||
}
|
||||
payloadSize += *seibuf;
|
||||
payloadSize += *seibuf;
|
||||
seibuf++;
|
||||
|
||||
|
||||
int broken=0;
|
||||
unsigned char *paystart = seibuf;
|
||||
seibuf+=payloadSize;
|
||||
|
||||
|
||||
dvprint("Payload type: %d size: %d - ", payloadType, payloadSize);
|
||||
if(seibuf > seiend )
|
||||
if(seibuf > seiend )
|
||||
{
|
||||
// TODO: What do we do here?
|
||||
broken=1;
|
||||
if (payloadType==4)
|
||||
if (payloadType==4)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Warning: Subtitles payload seems incorrect (too long), continuing but it doesn't look good..");
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Warning: Non-subtitles payload seems incorrect (too long), continuing but it doesn't look good..");
|
||||
}
|
||||
@@ -352,7 +354,7 @@ void copy_ccdata_to_buffer (char *source, int new_cc_count)
|
||||
mprint ("Warning: Probably loss of CC data, unsaved buffer being rewritten\n");
|
||||
ccblocks_in_avc_lost++;
|
||||
}
|
||||
memcpy(cc_data+cc_count*3, source, new_cc_count*3+1);
|
||||
memcpy(cc_data+cc_count*3, source, new_cc_count*3+1);
|
||||
cc_count+=new_cc_count;
|
||||
cc_buffer_saved=0;
|
||||
}
|
||||
@@ -393,7 +395,7 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
}
|
||||
|
||||
switch (itu_t_35_provider_code)
|
||||
{
|
||||
{
|
||||
case 0x0031: // ANSI/SCTE 128
|
||||
dbg_print(CCX_DMT_VERBOSE, "Caption block in ANSI/SCTE 128...");
|
||||
if (*tbuf==0x47 && *(tbuf+1)==0x41 && *(tbuf+2)==0x39 && *(tbuf+3)==0x34) // ATSC1_data() - GA94
|
||||
@@ -419,14 +421,14 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
*/
|
||||
local_cc_count= *tbuf & 0x1F;
|
||||
process_cc_data_flag = (*tbuf & 0x40) >> 6;
|
||||
|
||||
|
||||
/* if (!process_cc_data_flag)
|
||||
{
|
||||
mprint ("process_cc_data_flag == 0, skipping this caption block.\n");
|
||||
break;
|
||||
} */
|
||||
/*
|
||||
The following tests are not passed in Comcast's sample videos. *tbuf here is always 0x41.
|
||||
The following tests are not passed in Comcast's sample videos. *tbuf here is always 0x41.
|
||||
if (! (*tbuf & 0x80)) // First bit must be 1
|
||||
{
|
||||
printf ("Fixed bit should be 1, but it's 0 - skipping this caption block.\n");
|
||||
@@ -478,19 +480,19 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
default:
|
||||
dbg_print(CCX_DMT_VERBOSE, "SCTE/ATSC reserved.\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (*tbuf==0x44 && *(tbuf+1)==0x54 && *(tbuf+2)==0x47 && *(tbuf+3)==0x31) // afd_data() - DTG1
|
||||
{
|
||||
;
|
||||
// Active Format Description Data. Actually unrelated to captions. Left
|
||||
// here in case we want to do some reporting eventually. From specs:
|
||||
// "Active Format Description (AFD) should be included in video user
|
||||
// data whenever the rectangular picture area containing useful
|
||||
// "Active Format Description (AFD) should be included in video user
|
||||
// data whenever the rectangular picture area containing useful
|
||||
// information does not extend to the full height or width of the coded
|
||||
// frame. AFD data may also be included in user data when the
|
||||
// frame. AFD data may also be included in user data when the
|
||||
// rectangular picture area containing
|
||||
// useful information extends to the fullheight and width of the
|
||||
// useful information extends to the fullheight and width of the
|
||||
// coded frame."
|
||||
}
|
||||
else
|
||||
@@ -505,7 +507,7 @@ void user_data_registered_itu_t_t35 (unsigned char *userbuf, unsigned char *user
|
||||
if(user_data_type_code != 0x03)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Not supported user_data_type_code: %02x\n",
|
||||
user_data_type_code);
|
||||
user_data_type_code);
|
||||
return;
|
||||
}
|
||||
tbuf++;
|
||||
@@ -583,8 +585,8 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
dvprint("level_idc= % 4lld (%#llX)\n",tmp,tmp);
|
||||
seq_parameter_set_id = ue(&q1);
|
||||
dvprint("seq_parameter_set_id= % 4lld (%#llX)\n", seq_parameter_set_id,seq_parameter_set_id);
|
||||
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
|
||||
|| profile_idc == 244 || profile_idc == 44 || profile_idc == 83
|
||||
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
|
||||
|| profile_idc == 244 || profile_idc == 44 || profile_idc == 83
|
||||
|| profile_idc == 86 || profile_idc == 118 || profile_idc == 128){
|
||||
LLONG chroma_format_idc = ue(&q1);
|
||||
dvprint("chroma_format_idc= % 4lld (%#llX)\n", chroma_format_idc,chroma_format_idc);
|
||||
@@ -646,7 +648,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
dvprint("pic_order_cnt_type= % 4d (%#X)\n", pic_order_cnt_type,pic_order_cnt_type);
|
||||
if( pic_order_cnt_type == 0 )
|
||||
{
|
||||
log2_max_pic_order_cnt_lsb = (int)ue(&q1);
|
||||
log2_max_pic_order_cnt_lsb = (int)ue(&q1);
|
||||
dvprint("log2_max_pic_order_cnt_lsb_minus4= % 4d (%#X)\n", log2_max_pic_order_cnt_lsb,log2_max_pic_order_cnt_lsb);
|
||||
log2_max_pic_order_cnt_lsb += 4; // 4 is added due to formula.
|
||||
}
|
||||
@@ -654,18 +656,18 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
{
|
||||
// CFS: Untested, just copied from specs.
|
||||
tmp= u(&q1,1);
|
||||
dvprint("delta_pic_order_always_zero_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
dvprint("delta_pic_order_always_zero_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = se(&q1);
|
||||
dvprint("offset_for_non_ref_pic= % 4lld (%#llX)\n",tmp,tmp);
|
||||
dvprint("offset_for_non_ref_pic= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp = se(&q1);
|
||||
dvprint("offset_for_top_to_bottom_field % 4lld (%#llX)\n",tmp,tmp);
|
||||
dvprint("offset_for_top_to_bottom_field % 4lld (%#llX)\n",tmp,tmp);
|
||||
LLONG num_ref_frame_in_pic_order_cnt_cycle = ue (&q1);
|
||||
dvprint("num_ref_frame_in_pic_order_cnt_cycle % 4lld (%#llX)\n", num_ref_frame_in_pic_order_cnt_cycle,num_ref_frame_in_pic_order_cnt_cycle);
|
||||
dvprint("num_ref_frame_in_pic_order_cnt_cycle % 4lld (%#llX)\n", num_ref_frame_in_pic_order_cnt_cycle,num_ref_frame_in_pic_order_cnt_cycle);
|
||||
for (int i=0; i<num_ref_frame_in_pic_order_cnt_cycle; i++)
|
||||
{
|
||||
tmp=se(&q1);
|
||||
dvprint("offset_for_ref_frame [%d / %d] = % 4lld (%#llX)\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp,tmp);
|
||||
}
|
||||
tmp=se(&q1);
|
||||
dvprint("offset_for_ref_frame [%d / %d] = % 4lld (%#llX)\n", i, num_ref_frame_in_pic_order_cnt_cycle, tmp,tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -673,7 +675,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
}
|
||||
|
||||
tmp=ue(&q1);
|
||||
dvprint("max_num_ref_frames= % 4lld (%#llX)\n",tmp,tmp);
|
||||
dvprint("max_num_ref_frames= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=u(&q1,1);
|
||||
dvprint("gaps_in_frame_num_value_allowed_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
tmp=ue(&q1);
|
||||
@@ -782,21 +784,21 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
dvprint("nal_hrd_parameters_present_flag= % 4lld (%#llX)\n",tmp,tmp);
|
||||
if ( tmp )
|
||||
{
|
||||
dvprint ("nal_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
dvprint ("nal_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
//printf("Boom nal_hrd\n");
|
||||
// exit(1);
|
||||
num_nal_hrd++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tmp1=u(&q1,1);
|
||||
dvprint("vcl_hrd_parameters_present_flag= %llX\n", tmp1);
|
||||
if ( tmp )
|
||||
{
|
||||
// TODO.
|
||||
mprint ("vcl_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
mprint ("vcl_hrd. Not implemented for now. Hopefully not needed. Skiping rest of NAL\n");
|
||||
num_vcl_hrd++;
|
||||
// exit(1);
|
||||
}
|
||||
}
|
||||
if ( tmp || tmp1 )
|
||||
{
|
||||
tmp=u(&q1,1);
|
||||
@@ -817,7 +819,7 @@ void seq_parameter_set_rbsp (unsigned char *seqbuf, unsigned char *seqend)
|
||||
|
||||
|
||||
// Process slice header in AVC data.
|
||||
void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
|
||||
void slice_header (struct lib_ccx_ctx *ctx, unsigned char *heabuf, unsigned char *heaend, int nal_unit_type, struct cc_subtitle *sub)
|
||||
{
|
||||
LLONG tmp;
|
||||
struct bitstream q1;
|
||||
@@ -903,7 +905,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
FrameNumOffset = lastframe_num + maxframe_num;
|
||||
else
|
||||
FrameNumOffset = lastframe_num;
|
||||
|
||||
|
||||
LLONG tempPicOrderCnt=0;
|
||||
if (IdrPicFlag == 1)
|
||||
tempPicOrderCnt=0;
|
||||
@@ -923,7 +925,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
else
|
||||
TopFieldOrderCnt = tempPicOrderCnt;
|
||||
|
||||
//pic_order_cnt_lsb=tempPicOrderCnt;
|
||||
//pic_order_cnt_lsb=tempPicOrderCnt;
|
||||
//pic_order_cnt_lsb=u(&q1,tempPicOrderCnt);
|
||||
//fatal(CCX_COMMON_EXIT_BUG_BUG, "AVC: pic_order_cnt_type != 0 not yet supported.");
|
||||
//TODO
|
||||
@@ -965,11 +967,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
|
||||
// Sometimes two P-slices follow each other, see garbled_dishHD.mpg,
|
||||
// in this case we only treat the first as a reference pic
|
||||
if (isref && frames_since_last_gop <= 3) // Used to be == 1, but the sample file
|
||||
if (isref && ctx->frames_since_last_gop <= 3) // Used to be == 1, but the sample file
|
||||
{ // 2014 SugarHouse Casino Mummers Parade Fancy Brigades_new.ts was garbled
|
||||
// Probably doing a proper PTS sort would be a better solution.
|
||||
isref = 0;
|
||||
dbg_print(CCX_DMT_TIME, "Ignoring this reference pic.\n");
|
||||
dbg_print(CCX_DMT_TIME, "Ignoring this reference pic.\n");
|
||||
}
|
||||
|
||||
// if slices are buffered - flush
|
||||
@@ -982,10 +984,10 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(sub);
|
||||
process_hdcc(ctx, sub);
|
||||
}
|
||||
last_gop_length = frames_since_last_gop;
|
||||
frames_since_last_gop=0;
|
||||
ctx->last_gop_length = ctx->frames_since_last_gop;
|
||||
ctx->frames_since_last_gop=0;
|
||||
last_gop_maxtref = maxtref;
|
||||
maxtref = 0;
|
||||
lastmaxidx = maxidx;
|
||||
@@ -1035,11 +1037,11 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
// Set maxtref
|
||||
if( current_tref > maxtref ) {
|
||||
maxtref = current_tref;
|
||||
}
|
||||
}
|
||||
// Now an ugly workaround where pic_order_cnt_lsb increases in
|
||||
// steps of two. The 1.5 is an approximation, it should be:
|
||||
// last_gop_maxtref+1 == last_gop_length*2
|
||||
if ( last_gop_maxtref > last_gop_length*1.5 ) {
|
||||
if ( last_gop_maxtref > ctx->last_gop_length*1.5 ) {
|
||||
current_tref = current_tref/2;
|
||||
}
|
||||
}
|
||||
@@ -1078,7 +1080,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
}
|
||||
if ( lastmaxidx == -1) {
|
||||
// Set temporal reference to zero on minimal index and in the first GOP
|
||||
// to avoid setting a wrong fts_offset
|
||||
// to avoid setting a wrong fts_offset
|
||||
current_tref = 0;
|
||||
}
|
||||
}
|
||||
@@ -1098,7 +1100,7 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
(unsigned) (sync_pts));
|
||||
dbg_print(CCX_DMT_TIME, " - %s since GOP: %2u",
|
||||
slice_types[slice_type],
|
||||
(unsigned) (frames_since_last_gop));
|
||||
(unsigned) (ctx->frames_since_last_gop));
|
||||
dbg_print(CCX_DMT_TIME, " b:%lld frame# %lld\n", bottom_field_flag, frame_num);
|
||||
|
||||
// sync_pts is (was) set when current_tref was zero
|
||||
@@ -1112,9 +1114,9 @@ void slice_header (unsigned char *heabuf, unsigned char *heaend, int nal_unit_ty
|
||||
}
|
||||
|
||||
total_frames_count++;
|
||||
frames_since_last_gop++;
|
||||
ctx->frames_since_last_gop++;
|
||||
|
||||
store_hdcc(cc_data, cc_count, curridx, fts_now, sub);
|
||||
store_hdcc(ctx, cc_data, cc_count, curridx, fts_now, sub);
|
||||
cc_buffer_saved=1; // CFS: store_hdcc supposedly saves the CC buffer to a sequence buffer
|
||||
cc_count=0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
|
||||
// Hold functions to read streams on a bit or byte oriented basis
|
||||
// plus some data related helper functions.
|
||||
@@ -22,7 +22,7 @@ int init_bitstream(struct bitstream *bstr, unsigned char *start, unsigned char *
|
||||
bstr->_i_bpos = 0;
|
||||
|
||||
if(bstr->bitsleft < 0)
|
||||
{
|
||||
{
|
||||
// See if we can somehow recover of this disaster by reporting the problem instead of terminating.
|
||||
mprint ( "init_bitstream: bitstream has negative length!");
|
||||
return 1;
|
||||
@@ -300,11 +300,11 @@ uint64_t bitstream_get_num(struct bitstream *bstr, unsigned bytes, int advance)
|
||||
}
|
||||
for (unsigned i=0;i<bytes;i++)
|
||||
{
|
||||
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
|
||||
unsigned char uc=*ucpos;
|
||||
unsigned char *ucpos=((unsigned char *)bpos) +bytes-i-1; // Read backwards
|
||||
unsigned char uc=*ucpos;
|
||||
rval=(rval<<8) + uc;
|
||||
}
|
||||
return rval;
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ int64_t se(struct bitstream *bstr)
|
||||
int64_t res = 0;
|
||||
|
||||
res = ue(bstr);
|
||||
|
||||
|
||||
// The following function might truncate when res+1 overflows
|
||||
//res = (res+1)/2 * (res % 2 ? 1 : -1);
|
||||
// Use this:
|
||||
@@ -3,8 +3,8 @@
|
||||
void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
{
|
||||
unsigned char c1='?';
|
||||
if (c<0x80)
|
||||
{
|
||||
if (c<0x80)
|
||||
{
|
||||
// Regular line-21 character set, mostly ASCII except these exceptions
|
||||
switch (c)
|
||||
{
|
||||
@@ -16,7 +16,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
break;
|
||||
case 0x5e: // lowercase i, acute accent
|
||||
c1=0xed;
|
||||
break;
|
||||
break;
|
||||
case 0x5f: // lowercase o, acute accent
|
||||
c1=0xf3;
|
||||
break;
|
||||
@@ -45,25 +45,25 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
switch (c)
|
||||
{
|
||||
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
case 0x80: // Registered symbol (R)
|
||||
c1=0xae;
|
||||
break;
|
||||
break;
|
||||
case 0x81: // degree sign
|
||||
c1=0xb0;
|
||||
break;
|
||||
case 0x82: // 1/2 symbol
|
||||
case 0x82: // 1/2 symbol
|
||||
c1=0xbd;
|
||||
break;
|
||||
case 0x83: // Inverted (open) question mark
|
||||
case 0x83: // Inverted (open) question mark
|
||||
c1=0xbf;
|
||||
break;
|
||||
case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1
|
||||
break;
|
||||
case 0x85: // Cents symbol
|
||||
break;
|
||||
case 0x85: // Cents symbol
|
||||
c1=0xa2;
|
||||
break;
|
||||
case 0x86: // Pounds sterling
|
||||
case 0x86: // Pounds sterling
|
||||
c1=0xa3;
|
||||
break;
|
||||
case 0x87: // Music note - Not in latin 1, so we use 'pilcrow'
|
||||
@@ -73,7 +73,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
c1=0xe0;
|
||||
break;
|
||||
case 0x89: // transparent space, we make it regular
|
||||
c1=0x20;
|
||||
c1=0x20;
|
||||
break;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
c1=0xe8;
|
||||
@@ -82,7 +82,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
c1=0xe2;
|
||||
break;
|
||||
case 0x8c: // lowercase e, circumflex accent
|
||||
c1=0xea;
|
||||
c1=0xea;
|
||||
break;
|
||||
case 0x8d: // lowercase i, circumflex accent
|
||||
c1=0xee;
|
||||
@@ -114,19 +114,19 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
c1=0xfc;
|
||||
break;
|
||||
case 0x96: // apostrophe
|
||||
c1=0x27;
|
||||
c1=0x27;
|
||||
break;
|
||||
case 0x97: // inverted exclamation mark
|
||||
case 0x97: // inverted exclamation mark
|
||||
c1=0xa1;
|
||||
break;
|
||||
case 0x98: // asterisk
|
||||
c1=0x2a;
|
||||
c1=0x2a;
|
||||
break;
|
||||
case 0x99: // apostrophe (yes, duped). See CCADI source code.
|
||||
c1=0x27;
|
||||
c1=0x27;
|
||||
break;
|
||||
case 0x9a: // em dash
|
||||
c1=0x2d;
|
||||
c1=0x2d;
|
||||
break;
|
||||
case 0x9b: // copyright sign
|
||||
c1=0xa9;
|
||||
@@ -137,17 +137,17 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
c1=0x2e;
|
||||
break;
|
||||
case 0x9e: // Quoatation mark
|
||||
c1=0x22;
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0x9f: // Quoatation mark
|
||||
c1=0x22;
|
||||
c1=0x22;
|
||||
break;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
c1=0xc0;
|
||||
break;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
c1=0xc2;
|
||||
break;
|
||||
break;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
c1=0xc7;
|
||||
break;
|
||||
@@ -223,7 +223,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
c1=0x7b;
|
||||
break;
|
||||
case 0xba: // Closing curly brace
|
||||
c1=0x7d;
|
||||
c1=0x7d;
|
||||
break;
|
||||
case 0xbb: // Backslash
|
||||
c1=0x5c;
|
||||
@@ -234,17 +234,17 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
case 0xbd: // Underscore
|
||||
c1=0x5f;
|
||||
break;
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
c1=0xa6;
|
||||
break;
|
||||
case 0xbf: // Tilde
|
||||
c1=0x7e;
|
||||
c1=0x7e;
|
||||
break;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
c1=0xc4;
|
||||
break;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
c1=0xe3;
|
||||
c1=0xe3;
|
||||
break;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
c1=0xd6;
|
||||
@@ -260,10 +260,10 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
break;
|
||||
case 0xc6: // Currency symbol
|
||||
c1=0xa4;
|
||||
break;
|
||||
break;
|
||||
case 0xc7: // Vertical bar
|
||||
c1=0x7c;
|
||||
break;
|
||||
break;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
c1=0xc5;
|
||||
break;
|
||||
@@ -284,7 +284,7 @@ void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
|
||||
*buffer='?'; // I'll do it eventually, I promise
|
||||
break; // This are weird chars anyway
|
||||
}
|
||||
*buffer=c1;
|
||||
*buffer=c1;
|
||||
}
|
||||
|
||||
void get_char_in_unicode (unsigned char *buffer, unsigned char c)
|
||||
@@ -292,7 +292,7 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
|
||||
unsigned char c1,c2;
|
||||
switch (c)
|
||||
{
|
||||
case 0x84: // Trademark symbol (TM)
|
||||
case 0x84: // Trademark symbol (TM)
|
||||
c2=0x21;
|
||||
c1=0x22;
|
||||
break;
|
||||
@@ -307,7 +307,7 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
|
||||
case 0xcc: // Upper left corner
|
||||
c2=0x23;
|
||||
c1=0x1c;
|
||||
break;
|
||||
break;
|
||||
case 0xcd: // Upper right corner
|
||||
c2=0x23;
|
||||
c1=0x1d;
|
||||
@@ -320,7 +320,7 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
|
||||
c2=0x23;
|
||||
c1=0x1f;
|
||||
break;
|
||||
default: // Everything else, same as latin-1 followed by 00
|
||||
default: // Everything else, same as latin-1 followed by 00
|
||||
get_char_in_latin_1 (&c1,c);
|
||||
c2=0;
|
||||
break;
|
||||
@@ -384,10 +384,10 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
switch (c)
|
||||
{
|
||||
// THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
// THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
|
||||
case 0x80: // Registered symbol (R)
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xae;
|
||||
*(buffer+1)=0xae;
|
||||
return 2;
|
||||
case 0x81: // degree sign
|
||||
*buffer=0xc2;
|
||||
@@ -414,7 +414,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa3;
|
||||
return 2;
|
||||
case 0x87: // Music note
|
||||
case 0x87: // Music note
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x99;
|
||||
*(buffer+2)=0xaa;
|
||||
@@ -424,7 +424,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*(buffer+1)=0xa0;
|
||||
return 2;
|
||||
case 0x89: // transparent space, we make it regular
|
||||
*buffer=0x20;
|
||||
*buffer=0x20;
|
||||
return 1;
|
||||
case 0x8a: // lowercase e, grave accent
|
||||
*buffer=0xc3;
|
||||
@@ -477,20 +477,20 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*(buffer+1)=0xbc;
|
||||
return 2;
|
||||
case 0x96: // apostrophe
|
||||
*buffer=0x27;
|
||||
*buffer=0x27;
|
||||
return 1;
|
||||
case 0x97: // inverted exclamation mark
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa1;
|
||||
return 2;
|
||||
case 0x98: // asterisk
|
||||
*buffer=0x2a;
|
||||
*buffer=0x2a;
|
||||
return 1;
|
||||
case 0x99: // Plain single quote
|
||||
*buffer=0x27;
|
||||
*buffer=0x27;
|
||||
return 1;
|
||||
case 0x9a: // em dash
|
||||
*buffer=0xe2;
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x94;
|
||||
return 3;
|
||||
@@ -498,23 +498,23 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa9;
|
||||
return 2;
|
||||
case 0x9c: // Service mark
|
||||
*buffer=0xe2;
|
||||
case 0x9c: // Service mark
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x84;
|
||||
*(buffer+2)=0xa0;
|
||||
return 3;
|
||||
case 0x9d: // Round bullet
|
||||
*buffer=0xe2;
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0xa2;
|
||||
return 3;
|
||||
case 0x9e: // Opening double quotes
|
||||
*buffer=0xe2;
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x9c;
|
||||
return 3;
|
||||
case 0x9f: // Closing double quotes
|
||||
*buffer=0xe2;
|
||||
*buffer=0xe2;
|
||||
*(buffer+1)=0x80;
|
||||
*(buffer+2)=0x9d;
|
||||
return 3;
|
||||
@@ -624,7 +624,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*buffer=0x7b;
|
||||
return 1;
|
||||
case 0xba: // Closing curly brace
|
||||
*buffer=0x7d;
|
||||
*buffer=0x7d;
|
||||
return 1;
|
||||
case 0xbb: // Backslash
|
||||
*buffer=0x5c;
|
||||
@@ -636,26 +636,26 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*buffer=0x5f;
|
||||
return 1;
|
||||
case 0xbe: // Pipe (broken bar)
|
||||
*buffer=0xc2;
|
||||
*buffer=0xc2;
|
||||
*(buffer+1)=0xa6;
|
||||
return 2;
|
||||
case 0xbf: // Tilde
|
||||
*buffer=0x7e; // Not sure
|
||||
return 1;
|
||||
case 0xc0: // Uppercase A, umlaut
|
||||
*buffer=0xc3;
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x84;
|
||||
return 2;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
*buffer=0xc3;
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xa4;
|
||||
return 2;
|
||||
case 0xc2: // Uppercase O, umlaut
|
||||
*buffer=0xc3;
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0x96;
|
||||
return 2;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
*buffer=0xc3;
|
||||
*buffer=0xc3;
|
||||
*(buffer+1)=0xb6;
|
||||
return 2;
|
||||
case 0xc4: // Esszett (sharp S)
|
||||
@@ -671,7 +671,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*(buffer+1)=0xa4;
|
||||
return 2;
|
||||
case 0xc7: // Vertical bar
|
||||
*buffer=0x7c;
|
||||
*buffer=0x7c;
|
||||
return 1;
|
||||
case 0xc8: // Uppercase A, ring
|
||||
*buffer=0xc3;
|
||||
@@ -709,7 +709,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
|
||||
*(buffer+1)=0x8c;
|
||||
*(buffer+2)=0x9f;
|
||||
return 3;
|
||||
default: //
|
||||
default: //
|
||||
*buffer='?'; // I'll do it eventually, I promise
|
||||
return 1; // This are weird chars anyway
|
||||
}
|
||||
@@ -726,35 +726,35 @@ unsigned char cctolower (unsigned char c)
|
||||
case 0x90: // capital letter A with acute
|
||||
return 0x2a;
|
||||
case 0x91: // capital letter E with acute
|
||||
return 0x5c;
|
||||
return 0x5c;
|
||||
case 0x92: // capital letter O with acute
|
||||
return 0x5f;
|
||||
return 0x5f;
|
||||
case 0x93: // capital letter U with acute
|
||||
return 0x60;
|
||||
return 0x60;
|
||||
case 0xa2: // uppercase C with cedilla
|
||||
return 0x7b;
|
||||
return 0x7b;
|
||||
case 0xa0: // uppercase A, grave accent
|
||||
return 0x88;
|
||||
return 0x88;
|
||||
case 0xa3: // uppercase E, grave accent
|
||||
return 0x8a;
|
||||
return 0x8a;
|
||||
case 0xa1: // uppercase A, circumflex
|
||||
return 0x8b;
|
||||
return 0x8b;
|
||||
case 0xa4: // uppercase E, circumflex
|
||||
return 0x8c;
|
||||
return 0x8c;
|
||||
case 0xa7: // uppercase I, circumflex
|
||||
return 0x8d;
|
||||
return 0x8d;
|
||||
case 0xaa: // uppercase O, circumflex
|
||||
return 0x8e;
|
||||
return 0x8e;
|
||||
case 0xad: // uppercase U, circumflex
|
||||
return 0x8f;
|
||||
return 0x8f;
|
||||
case 0x94: // capital letter U with diaresis
|
||||
return 0x95;
|
||||
return 0x95;
|
||||
case 0xa5: // capital letter E with diaresis
|
||||
return 0xa6;
|
||||
return 0xa6;
|
||||
case 0xa8: // uppercase I, with diaresis
|
||||
return 0xa9;
|
||||
return 0xa9;
|
||||
case 0xab: // uppercase U, grave accent
|
||||
return 0xac;
|
||||
return 0xac;
|
||||
case 0xb0: // Uppercase A, tilde
|
||||
return 0xb1;
|
||||
case 0xb2: // Uppercase I, acute accent
|
||||
@@ -820,21 +820,21 @@ unsigned char cctoupper (unsigned char c)
|
||||
case 0xac: // lowercase u, grave accent
|
||||
return 0xab;
|
||||
case 0xb1: // Lowercase a, tilde
|
||||
return 0xb0;
|
||||
return 0xb0;
|
||||
case 0xb4: // Lowercase i, grave accent
|
||||
return 0xb3;
|
||||
case 0xb6: // Lowercase o, grave accent
|
||||
return 0xb5;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
return 0xb5;
|
||||
case 0xb8: // Lowercase o, tilde
|
||||
return 0xb7;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
return 0xc0;
|
||||
case 0xc1: // Lowercase A, umlaut
|
||||
return 0xc0;
|
||||
case 0xc3: // Lowercase o, umlaut
|
||||
return 0xc2;
|
||||
case 0xc9: // Lowercase A, ring
|
||||
return 0xc8;
|
||||
return 0xc8;
|
||||
case 0xcb: // Lowercase o, slash
|
||||
return 0xca;
|
||||
return 0xca;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -13,5 +13,8 @@
|
||||
void fdprintf(int fd, const char *fmt, ...);
|
||||
void mstotime(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms);
|
||||
void freep(void *arg);
|
||||
void dbg_print(LLONG mask, const char *fmt, ...);
|
||||
unsigned char *debug_608toASC(unsigned char *ccdata, int channel);
|
||||
|
||||
#endif
|
||||
extern int cc608_parity_table[256]; // From myth
|
||||
#endif
|
||||
@@ -124,10 +124,15 @@ enum
|
||||
DTVCC_PACKET_START = 3,
|
||||
};
|
||||
|
||||
const char *language[4] =
|
||||
/**
|
||||
* After Adding a new language here, dont forget
|
||||
* to increase NB_LANGUAGE define ccx_common_constants.h
|
||||
*/
|
||||
const char *language[NB_LANGUAGE] =
|
||||
{
|
||||
"und",
|
||||
"eng",
|
||||
"fin",
|
||||
"spa",
|
||||
NULL
|
||||
};
|
||||
@@ -39,16 +39,16 @@ extern unsigned char rcwt_header[11];
|
||||
|
||||
#define XMLRPC_CHUNK_SIZE (64*1024) // 64 Kb per chunk, to avoid too many realloc()
|
||||
|
||||
enum ccx_debug_message_types
|
||||
enum ccx_debug_message_types
|
||||
{
|
||||
/* Each debug message now belongs to one of these types. Use bitmaps in case
|
||||
we want one message to belong to more than one type. */
|
||||
/* Each debug message now belongs to one of these types. Use bitmaps in case
|
||||
we want one message to belong to more than one type. */
|
||||
CCX_DMT_PARSE=1, // Show information related to parsing the container
|
||||
CCX_DMT_VIDES=2,// Show video stream related information
|
||||
CCX_DMT_TIME=4, // Show GOP and PTS timing information
|
||||
CCX_DMT_VERBOSE=8, // Show lots of debugging output
|
||||
CCX_DMT_DECODER_608=0x10, // Show CC-608 decoder debug?
|
||||
CCX_DMT_708=0x20, // Show CC-708 decoder debug?
|
||||
CCX_DMT_DECODER_608=0x10, // Show CC-608 decoder debug?
|
||||
CCX_DMT_708=0x20, // Show CC-708 decoder debug?
|
||||
CCX_DMT_DECODER_XDS=0x40, // Show XDS decoder debug?
|
||||
CCX_DMT_CBRAW=0x80, // Caption blocks with FTS timing
|
||||
CCX_DMT_GENERIC_NOTICES=0x100, // Generic, always displayed even if no debug is selected
|
||||
@@ -81,7 +81,7 @@ enum ccx_avc_nal_types
|
||||
CCX_NAL_TYPE_RESERVED_17 = 18,
|
||||
CCX_NAL_TYPE_RESERVED_18 = 18,
|
||||
CCX_NAL_TYPE_CODED_SLICE_AUXILIARY_PICTURE = 19,
|
||||
CCX_NAL_TYPE_CODED_SLICE_EXTENSION = 20,
|
||||
CCX_NAL_TYPE_CODED_SLICE_EXTENSION = 20,
|
||||
CCX_NAL_TYPE_RESERVED_21 = 21,
|
||||
CCX_NAL_TYPE_RESERVED_22 = 22,
|
||||
CCX_NAL_TYPE_RESERVED_23 = 23,
|
||||
@@ -108,7 +108,7 @@ enum ccx_stream_type
|
||||
CCX_STREAM_TYPE_PRIVATE_MPEG2 = 0x06,
|
||||
CCX_STREAM_TYPE_MHEG_PACKETS = 0x07,
|
||||
CCX_STREAM_TYPE_MPEG2_ANNEX_A_DSM_CC = 0x08,
|
||||
CCX_STREAM_TYPE_ITU_T_H222_1 = 0x09,
|
||||
CCX_STREAM_TYPE_ITU_T_H222_1 = 0x09,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_A = 0x0A,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_B = 0x0B,
|
||||
CCX_STREAM_TYPE_ISO_IEC_13818_6_TYPE_C = 0x0C,
|
||||
@@ -124,13 +124,14 @@ enum ccx_stream_type
|
||||
|
||||
enum ccx_mpeg_descriptor
|
||||
{
|
||||
CCX_MPEG_DSC_REGISTRATION = 0x05,
|
||||
CCX_MPEG_DSC_REGISTRATION = 0x05,
|
||||
CCX_MPEG_DSC_DATA_STREAM_ALIGNMENT = 0x06,
|
||||
CCX_MPEG_DSC_ISO639_LANGUAGE = 0x0A,
|
||||
CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR = 0x45,
|
||||
CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR = 0x46,
|
||||
CCX_MPEG_DSC_TELETEXT_DESCRIPTOR = 0x56,
|
||||
CCX_MPEG_DSC_DVB_SUBTITLE = 0x59,
|
||||
CCX_MPEG_DESC_DATA_COMP = 0xfd,
|
||||
};
|
||||
|
||||
|
||||
@@ -222,11 +223,12 @@ typedef enum {
|
||||
UNDEF = 0xff
|
||||
} bool_t;
|
||||
|
||||
enum cxx_code_type
|
||||
enum ccx_code_type
|
||||
{
|
||||
CCX_CODEC_ANY,
|
||||
CCX_CODEC_TELETEXT,
|
||||
CCX_CODEC_DVB,
|
||||
CCX_CODEC_ISDB_CC,
|
||||
CCX_CODEC_NONE,
|
||||
};
|
||||
/*
|
||||
@@ -236,13 +238,13 @@ enum cxx_code_type
|
||||
* @param desc descriptor tag given for each stream
|
||||
*
|
||||
* @return if descriptor tag is valid then it return 1 otherwise 0
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define IS_VALID_TELETEXT_DESC(desc) ( ((desc) == CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR )|| \
|
||||
( (desc) == CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR ) || \
|
||||
( (desc) == CCX_MPEG_DSC_TELETEXT_DESCRIPTOR ) )
|
||||
|
||||
|
||||
/*
|
||||
* This macro to be used when you want to find out whether you
|
||||
* should parse f_sel subtitle codec type or not
|
||||
@@ -265,5 +267,6 @@ enum cxx_code_type
|
||||
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
|
||||
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc
|
||||
|
||||
extern const char *language[4];
|
||||
#define NB_LANGUAGE 5
|
||||
extern const char *language[NB_LANGUAGE];
|
||||
#endif
|
||||
105
src/lib_ccx/ccx_common_option.c
Normal file
105
src/lib_ccx/ccx_common_option.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "utility.h"
|
||||
|
||||
struct ccx_s_options ccx_options;
|
||||
/* Parameters */
|
||||
void init_options (struct ccx_s_options *options)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
options->buffer_input = 1; // In Windows buffering seems to help
|
||||
options->no_bom = 0;
|
||||
#else
|
||||
options->buffer_input = 0; // In linux, not so much.
|
||||
options->no_bom = 1;
|
||||
#endif
|
||||
options->nofontcolor=0; // 1 = don't put <font color> tags
|
||||
options->notypesetting=0; // 1 = Don't put <i>, <u>, etc typesetting tags
|
||||
|
||||
options->no_bom = 0; // Use BOM by default.
|
||||
|
||||
options->settings_608.direct_rollup = 0;
|
||||
options->settings_608.no_rollup = 0;
|
||||
options->settings_608.force_rollup = 0;
|
||||
options->settings_608.screens_to_process = -1;
|
||||
options->settings_608.default_color = COL_TRANSPARENT; // Defaults to transparant/no-color.
|
||||
|
||||
/* Select subtitle codec */
|
||||
options->codec = CCX_CODEC_ANY;
|
||||
options->nocodec = CCX_CODEC_NONE;
|
||||
|
||||
/* Credit stuff */
|
||||
options->start_credits_text=NULL;
|
||||
options->end_credits_text=NULL;
|
||||
options->extract = 1; // Extract 1st field only (primary language)
|
||||
options->cc_channel = 1; // Channel we want to dump in srt mode
|
||||
options->binary_concat=1; // Disabled by -ve or --videoedited
|
||||
options->use_gop_as_pts = 0; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
|
||||
options->fix_padding = 0; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
options->trim_subs=0; // " Remove spaces at sides? "
|
||||
options->gui_mode_reports=0; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
options->no_progress_bar=0; // If 1, suppress the output of the progress to stdout
|
||||
options->sentence_cap =0 ; // FIX CASE? = Fix case?
|
||||
options->sentence_cap_file=NULL; // Extra words file?
|
||||
options->live_stream=0; // 0 -> A regular file
|
||||
options->messages_target=1; // 1=stdout
|
||||
options->print_file_reports=0;
|
||||
/* Levenshtein's parameters, for string comparison */
|
||||
options->levdistmincnt=2; // Means 2 fails or less is "the same"...
|
||||
options->levdistmaxpct=10; // ...10% or less is also "the same"
|
||||
options->investigate_packets = 0; // Look for captions in all packets when everything else fails
|
||||
options->fullbin=0; // Disable pruning of padding cc blocks
|
||||
options->nosync=0; // Disable syncing
|
||||
options->hauppauge_mode=0; // If 1, use PID=1003, process specially and so on
|
||||
options->wtvconvertfix = 0; // Fix broken Windows 7 conversion
|
||||
options->wtvmpeg2 = 0;
|
||||
options->auto_myth = 2; // 2=auto
|
||||
/* MP4 related stuff */
|
||||
options->mp4vidtrack=0; // Process the video track even if a CC dedicated track exists.
|
||||
/* General stuff */
|
||||
options->usepicorder = 0; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
|
||||
options->autodash=0; // Add dashes (-) before each speaker automatically?
|
||||
options->teletext_mode=CCX_TXT_AUTO_NOT_YET_FOUND; // 0=Disabled, 1 = Not found, 2=Found
|
||||
|
||||
options->transcript_settings = ccx_encoders_default_transcript_settings;
|
||||
options->millis_separator=',';
|
||||
|
||||
options->encoding = CCX_ENC_UTF_8;
|
||||
options->write_format=CCX_OF_SRT; // 0=Raw, 1=srt, 2=SMI
|
||||
options->date_format=ODF_NONE;
|
||||
options->output_filename=NULL;
|
||||
options->out_elementarystream_filename=NULL;
|
||||
options->debug_mask=CCX_DMT_GENERIC_NOTICES; // dbg_print will use this mask to print or ignore different types
|
||||
options->debug_mask_on_debug=CCX_DMT_VERBOSE; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
|
||||
options->ts_autoprogram =0; // Try to find a stream with captions automatically (no -pn needed)
|
||||
options->ts_cappid = 0; // PID for stream that holds caption information
|
||||
options->ts_forced_cappid = 0; // If 1, never mess with the selected PID
|
||||
options->ts_forced_program=0; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
options->ts_forced_program_selected=0;
|
||||
options->ts_datastreamtype = -1; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
options->ts_forced_streamtype=CCX_STREAM_TYPE_UNKNOWNSTREAM; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
options->udpaddr = NULL;
|
||||
options->udpport=0; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
options->send_to_srv = 0;
|
||||
options->tcpport = NULL;
|
||||
options->tcp_password = NULL;
|
||||
options->tcp_desc = NULL;
|
||||
options->srv_addr = NULL;
|
||||
options->srv_port = NULL;
|
||||
options->line_terminator_lf=0; // 0 = CRLF
|
||||
options->noautotimeref=0; // Do NOT set time automatically?
|
||||
options->input_source=CCX_DS_FILE; // Files, stdin or network
|
||||
options->auto_stream = CCX_SM_AUTODETECT;
|
||||
|
||||
// Prepare time structures
|
||||
init_boundary_time (&options->extraction_start);
|
||||
init_boundary_time (&options->extraction_end);
|
||||
init_boundary_time (&options->startcreditsnotbefore);
|
||||
init_boundary_time (&options->startcreditsnotafter);
|
||||
init_boundary_time (&options->startcreditsforatleast);
|
||||
init_boundary_time (&options->startcreditsforatmost);
|
||||
init_boundary_time (&options->endcreditsforatleast);
|
||||
init_boundary_time (&options->endcreditsforatmost);
|
||||
|
||||
}
|
||||
98
src/lib_ccx/ccx_common_option.h
Normal file
98
src/lib_ccx/ccx_common_option.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef CCX_COMMON_OPTION_H
|
||||
#define CCX_COMMON_OPTION_H
|
||||
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_encoders_structs.h"
|
||||
struct ccx_s_options // Options from user parameters
|
||||
{
|
||||
int extract; // Extract 1st, 2nd or both fields
|
||||
int cc_channel; // Channel we want to dump in srt mode
|
||||
int buffer_input;
|
||||
int nofontcolor;
|
||||
int notypesetting;
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
int print_file_reports;
|
||||
|
||||
int no_bom; // Set to 1 when no BOM (Byte Order Mark) should be used for files. Note, this might make files unreadable in windows!
|
||||
|
||||
ccx_decoder_608_settings settings_608; // Contains the settings for the 608 decoder.
|
||||
|
||||
/* subtitle codec type */
|
||||
enum ccx_code_type codec;
|
||||
enum ccx_code_type nocodec;
|
||||
/* Credit stuff */
|
||||
char *start_credits_text;
|
||||
char *end_credits_text;
|
||||
struct ccx_boundary_time startcreditsnotbefore, startcreditsnotafter; // Where to insert start credits, if possible
|
||||
struct ccx_boundary_time startcreditsforatleast, startcreditsforatmost; // How long to display them?
|
||||
struct ccx_boundary_time endcreditsforatleast, endcreditsforatmost;
|
||||
int binary_concat; // Disabled by -ve or --videoedited
|
||||
int use_gop_as_pts; // Use GOP instead of PTS timing (0=do as needed, 1=always, -1=never)
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
int trim_subs; // " Remove spaces at sides? "
|
||||
int gui_mode_reports; // If 1, output in stderr progress updates so the GUI can grab them
|
||||
int no_progress_bar; // If 1, suppress the output of the progress to stdout
|
||||
int sentence_cap ; // FIX CASE? = Fix case?
|
||||
char *sentence_cap_file; // Extra words file?
|
||||
int live_stream; /* -1 -> Not a complete file but a live stream, without timeout
|
||||
0 -> A regular file
|
||||
>0 -> Live stream with a timeout of this value in seconds */
|
||||
int messages_target; // 0 = nowhere (quiet), 1=stdout, 2=stderr
|
||||
/* Levenshtein's parameters, for string comparison */
|
||||
int levdistmincnt, levdistmaxpct; // Means 2 fails or less is "the same", 10% or less is also "the same"
|
||||
int investigate_packets; // Look for captions in all packets when everything else fails
|
||||
int fullbin; // Disable pruning of padding cc blocks
|
||||
int nosync; // Disable syncing
|
||||
unsigned hauppauge_mode; // If 1, use PID=1003, process specially and so on
|
||||
int wtvconvertfix; // Fix broken Windows 7 conversion
|
||||
int wtvmpeg2;
|
||||
int auto_myth; // Use myth-tv mpeg code? 0=no, 1=yes, 2=auto
|
||||
/* MP4 related stuff */
|
||||
unsigned mp4vidtrack; // Process the video track even if a CC dedicated track exists.
|
||||
/* General settings */
|
||||
int usepicorder; // Force the use of pic_order_cnt_lsb in AVC/H.264 data streams
|
||||
int autodash; // Add dashes (-) before each speaker automatically?
|
||||
unsigned teletext_mode; // 0=Disabled, 1 = Not found, 2=Found
|
||||
ccx_encoders_transcript_format transcript_settings; // Keeps the settings for generating transcript output files.
|
||||
char millis_separator;
|
||||
enum ccx_encoding_type encoding;
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
enum ccx_output_date_format date_format;
|
||||
char *output_filename;
|
||||
char *out_elementarystream_filename;
|
||||
LLONG debug_mask; // dbg_print will use this mask to print or ignore different types
|
||||
LLONG debug_mask_on_debug; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1
|
||||
unsigned ts_autoprogram ; // Try to find a stream with captions automatically (no -pn needed)
|
||||
unsigned ts_cappid ; // PID for stream that holds caption information
|
||||
unsigned ts_forced_cappid ; // If 1, never mess with the selected PID
|
||||
unsigned ts_forced_program; // Specific program to process in TS files, if ts_forced_program_selected==1
|
||||
unsigned ts_forced_program_selected;
|
||||
int ts_datastreamtype ; // User WANTED stream type (i.e. use the stream that has this type)
|
||||
unsigned ts_forced_streamtype; // User selected (forced) stream type
|
||||
/* Networking */
|
||||
char *udpaddr;
|
||||
unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files.
|
||||
unsigned send_to_srv;
|
||||
char *tcpport;
|
||||
char *tcp_password;
|
||||
char *tcp_desc;
|
||||
char *srv_addr;
|
||||
char *srv_port;
|
||||
int line_terminator_lf; // 0 = CRLF, 1=LF
|
||||
int noautotimeref; // Do NOT set time automatically?
|
||||
enum ccx_datasource input_source; // Files, stdin or network
|
||||
|
||||
char **inputfile; // List of files to process
|
||||
int num_input_files; // How many?
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
// Output structures
|
||||
struct ccx_s_write wbout1;
|
||||
struct ccx_s_write wbout2;
|
||||
};
|
||||
|
||||
extern struct ccx_s_options ccx_options;
|
||||
void init_options (struct ccx_s_options *options);
|
||||
#endif
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -86,8 +86,8 @@
|
||||
#define LSEEK _lseeki64
|
||||
typedef struct _stati64 FSTATSTRUCT;
|
||||
#else
|
||||
// Linux internally maps these functions to 64bit usage,
|
||||
// if _FILE_OFFSET_BITS macro is set to 64
|
||||
// Linux internally maps these functions to 64bit usage,
|
||||
// if _FILE_OFFSET_BITS macro is set to 64
|
||||
#define FOPEN64 fopen
|
||||
#define OPEN open
|
||||
#define LSEEK lseek
|
||||
@@ -97,7 +97,7 @@
|
||||
#define TELL tell
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef int64_t_C
|
||||
#define int64_t_C(c) (c ## LL)
|
||||
@@ -9,12 +9,13 @@ enum ccx_common_logging_gui {
|
||||
};
|
||||
|
||||
struct ccx_common_logging_t {
|
||||
int debug_mask; // The debug mask that is used to determine if things should be printed or not.
|
||||
int debug_mask; // The debug mask that is used to determine if things should be printed or not.
|
||||
void(*fatal_ftn) (int exit_code, const char *fmt, ...); // Used when an unrecoverable error happens. This should log output/save the error and then exit the program.
|
||||
void(*debug_ftn) (LLONG mask, const char *fmt, ...); // Used to process debug output. Mask can be ignored (custom set by debug_mask).
|
||||
void(*log_ftn)(const char *fmt, ...); // Used to print things. Replacement of standard printf, to allow more control.
|
||||
void(*gui_ftn)(enum ccx_common_logging_gui message_type, ...); // Used to display things in a gui (if appropriate). Is called with the message_type and appropriate variables (described in enum)
|
||||
} ccx_common_logging;
|
||||
};
|
||||
extern struct ccx_common_logging_t ccx_common_logging;
|
||||
|
||||
enum subtype
|
||||
{
|
||||
@@ -49,4 +50,4 @@ struct cc_subtitle
|
||||
/** flag to tell that decoder has given output */
|
||||
int got_output;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
@@ -41,7 +41,10 @@ struct gop_time_code gop_time, first_gop_time, printed_gop;
|
||||
LLONG fts_at_gop_start = 0;
|
||||
int gop_rollover = 0;
|
||||
|
||||
void ccx_common_timing_init(LLONG *file_position,int no_sync){
|
||||
struct ccx_common_timing_settings_t ccx_common_timing_settings;
|
||||
|
||||
void ccx_common_timing_init(LLONG *file_position,int no_sync)
|
||||
{
|
||||
ccx_common_timing_settings.disable_sync_check = 0;
|
||||
ccx_common_timing_settings.is_elementary_stream = 0;
|
||||
ccx_common_timing_settings.file_position = file_position;
|
||||
@@ -111,7 +114,7 @@ void set_fts(void)
|
||||
}
|
||||
else if ( total_frames_count-frames_since_ref_time == 0 )
|
||||
{ // If this is the first frame (PES) there cannot be an offset.
|
||||
// This part is also reached for dvr-ms/NTSC (RAW) as
|
||||
// This part is also reached for dvr-ms/NTSC (RAW) as
|
||||
// total_frames_count = frames_since_ref_time = 0 when
|
||||
// this is called for the first time.
|
||||
fts_offset = 0;
|
||||
@@ -228,7 +231,7 @@ char *print_mstime2buf( LLONG mstime , char *buf )
|
||||
int signoffset = (mstime < 0 ? 1 : 0);
|
||||
|
||||
if (mstime<0) // Avoid loss of data warning with abs()
|
||||
mstime=-mstime;
|
||||
mstime=-mstime;
|
||||
hh = (unsigned) (mstime/1000/60/60);
|
||||
mm = (unsigned) (mstime/1000/60 - 60*hh);
|
||||
ss = (unsigned) (mstime/1000 - 60*(mm + 60*hh));
|
||||
@@ -286,9 +289,9 @@ void calculate_ms_gop_time (struct gop_time_code *g)
|
||||
|
||||
int gop_accepted(struct gop_time_code* g )
|
||||
{
|
||||
if (! ((g->time_code_hours <= 23)
|
||||
&& (g->time_code_minutes <= 59)
|
||||
&& (g->time_code_seconds <= 59)
|
||||
if (! ((g->time_code_hours <= 23)
|
||||
&& (g->time_code_minutes <= 59)
|
||||
&& (g->time_code_seconds <= 59)
|
||||
&& (g->time_code_pictures <= 59)))
|
||||
return 0;
|
||||
|
||||
@@ -19,7 +19,15 @@ struct ccx_common_timing_settings_t {
|
||||
int no_sync; // If 1, there will be no sync at all. Mostly useful for debugging.
|
||||
int is_elementary_stream; // Needs to be set, as it's used in set_fts.
|
||||
LLONG *file_position; // The position of the file
|
||||
} ccx_common_timing_settings;
|
||||
};
|
||||
extern struct ccx_common_timing_settings_t ccx_common_timing_settings;
|
||||
|
||||
struct ccx_boundary_time
|
||||
{
|
||||
int hh,mm,ss;
|
||||
LLONG time_in_ms;
|
||||
int set;
|
||||
};
|
||||
|
||||
// Count 608 (per field) and 708 blocks since last set_fts() call
|
||||
extern int cb_field1, cb_field2, cb_708;
|
||||
@@ -61,4 +69,4 @@ int gop_accepted(struct gop_time_code* g);
|
||||
void calculate_ms_gop_time(struct gop_time_code *g);
|
||||
|
||||
#define __Timing_H__
|
||||
#endif
|
||||
#endif
|
||||
@@ -116,42 +116,54 @@ void clear_eia608_cc_buffer(ccx_decoder_608_context *context, struct eia608_scre
|
||||
data->empty=1;
|
||||
}
|
||||
|
||||
ccx_decoder_608_context ccx_decoder_608_init_library(ccx_decoder_608_settings settings, int channel, int field, int trim_subs, enum ccx_encoding_type encoding, int *halt, int *cc_to_stdout)
|
||||
void ccx_decoder_608_dinit_library(void **ctx)
|
||||
{
|
||||
ccx_decoder_608_context data;
|
||||
freep(ctx);
|
||||
}
|
||||
ccx_decoder_608_context* ccx_decoder_608_init_library(ccx_decoder_608_settings settings, int channel,
|
||||
int field, int trim_subs,
|
||||
enum ccx_encoding_type encoding, int *halt,
|
||||
int cc_to_stdout, LLONG subs_delay,
|
||||
enum ccx_output_format output_format)
|
||||
{
|
||||
ccx_decoder_608_context *data = NULL;
|
||||
|
||||
data.cursor_column=0;
|
||||
data.cursor_row=0;
|
||||
data.visible_buffer=1;
|
||||
data.last_c1=0;
|
||||
data.last_c2=0;
|
||||
data.mode=MODE_POPON;
|
||||
// data.current_visible_start_cc=0;
|
||||
data.current_visible_start_ms=0;
|
||||
data.screenfuls_counter=0;
|
||||
data.channel=1;
|
||||
data.font=FONT_REGULAR;
|
||||
data.rollup_base_row=14;
|
||||
data.ts_start_of_current_line=-1;
|
||||
data.ts_last_char_received=-1;
|
||||
data.new_channel=1;
|
||||
data.bytes_processed_608 = 0;
|
||||
data.my_field = field;
|
||||
data.my_channel = channel;
|
||||
data.out = NULL;
|
||||
data.have_cursor_position = 0;
|
||||
data = malloc(sizeof(ccx_decoder_608_context));
|
||||
|
||||
data.trim_subs = trim_subs;
|
||||
data.encoding = encoding;
|
||||
|
||||
data.halt = halt;
|
||||
data.cc_to_stdout = cc_to_stdout;
|
||||
data->cursor_column=0;
|
||||
data->cursor_row=0;
|
||||
data->visible_buffer=1;
|
||||
data->last_c1=0;
|
||||
data->last_c2=0;
|
||||
data->mode=MODE_POPON;
|
||||
// data->current_visible_start_cc=0;
|
||||
data->current_visible_start_ms=0;
|
||||
data->screenfuls_counter=0;
|
||||
data->channel=1;
|
||||
data->font=FONT_REGULAR;
|
||||
data->rollup_base_row=14;
|
||||
data->ts_start_of_current_line=-1;
|
||||
data->ts_last_char_received=-1;
|
||||
data->new_channel=1;
|
||||
data->bytes_processed_608 = 0;
|
||||
data->my_field = field;
|
||||
data->my_channel = channel;
|
||||
data->out = NULL;
|
||||
data->have_cursor_position = 0;
|
||||
|
||||
data.settings = settings;
|
||||
data.current_color = data.settings.default_color;
|
||||
data->trim_subs = trim_subs;
|
||||
data->encoding = encoding;
|
||||
|
||||
clear_eia608_cc_buffer(&data, &data.buffer1);
|
||||
clear_eia608_cc_buffer(&data, &data.buffer2);
|
||||
data->halt = halt;
|
||||
data->cc_to_stdout = cc_to_stdout;
|
||||
data->subs_delay = subs_delay;
|
||||
data->output_format = output_format;
|
||||
|
||||
data->settings = settings;
|
||||
data->current_color = data->settings.default_color;
|
||||
|
||||
clear_eia608_cc_buffer(data, &data->buffer1);
|
||||
clear_eia608_cc_buffer(data, &data->buffer2);
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -284,7 +296,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
*context->halt=1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
data = get_current_visible_buffer(context);
|
||||
|
||||
if (context->mode == MODE_FAKE_ROLLUP_1 && // Use the actual start of data instead of last buffer change
|
||||
@@ -292,7 +304,7 @@ int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
context->current_visible_start_ms = context->ts_start_of_current_line;
|
||||
|
||||
start_time = context->current_visible_start_ms;
|
||||
end_time = get_visible_end() + ccx_decoders_common_settings.subs_delay;
|
||||
end_time = get_visible_end() + context->subs_delay;
|
||||
sub->type = CC_608;
|
||||
data->format = SFORMAT_CC_SCREEN;
|
||||
data->start_time = 0;
|
||||
@@ -347,17 +359,18 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
int wrote_something=0;
|
||||
int ret = 0;
|
||||
data = get_current_visible_buffer(context);
|
||||
|
||||
start_time = context->ts_start_of_current_line + ccx_decoders_common_settings.subs_delay;
|
||||
end_time = get_fts() + ccx_decoders_common_settings.subs_delay;
|
||||
|
||||
start_time = context->ts_start_of_current_line + context->subs_delay;
|
||||
end_time = get_fts() + context->subs_delay;
|
||||
sub->type = CC_608;
|
||||
data->format = SFORMAT_CC_LINE;
|
||||
data->format = SFORMAT_CC_LINE;
|
||||
data->start_time = 0;
|
||||
data->end_time = 0;
|
||||
data->mode = context->mode;
|
||||
data->channel = context->channel;
|
||||
data->my_field = context->my_field;
|
||||
|
||||
//TODO need to put below functionality in encoder context
|
||||
ret = get_decoder_line_basic (subline, context->cursor_row, data,context->trim_subs,context->encoding);
|
||||
if( ret > 0 )
|
||||
{
|
||||
@@ -400,7 +413,7 @@ int write_cc_line(ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
}
|
||||
}
|
||||
return wrote_something;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Check if a rollup would cause a line to go off the visible area
|
||||
@@ -728,7 +741,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
context->cursor_row++;
|
||||
break;
|
||||
}
|
||||
if (ccx_decoders_common_settings.output_format == CCX_OF_TRANSCRIPT)
|
||||
if (context->output_format == CCX_OF_TRANSCRIPT)
|
||||
{
|
||||
write_cc_line(context,sub);
|
||||
}
|
||||
@@ -739,7 +752,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
if (changes)
|
||||
{
|
||||
// Only if the roll up would actually cause a line to disappear we write the buffer
|
||||
if (ccx_decoders_common_settings.output_format != CCX_OF_TRANSCRIPT)
|
||||
if (context->output_format != CCX_OF_TRANSCRIPT)
|
||||
{
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
@@ -759,7 +772,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
case COM_ERASEDISPLAYEDMEMORY:
|
||||
// Write it to disk before doing this, and make a note of the new
|
||||
// time it became clear.
|
||||
if (ccx_decoders_common_settings.output_format == CCX_OF_TRANSCRIPT &&
|
||||
if (context->output_format == CCX_OF_TRANSCRIPT &&
|
||||
(context->mode == MODE_FAKE_ROLLUP_1 ||
|
||||
context->mode == MODE_ROLLUP_2 ||
|
||||
context->mode == MODE_ROLLUP_3 ||
|
||||
@@ -772,7 +785,7 @@ void handle_command(/*const */ unsigned char c1, const unsigned char c2, ccx_dec
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ccx_decoders_common_settings.output_format == CCX_OF_TRANSCRIPT)
|
||||
if (context->output_format == CCX_OF_TRANSCRIPT)
|
||||
context->ts_start_of_current_line = context->current_visible_start_ms;
|
||||
if (write_cc_buffer(context, sub))
|
||||
context->screenfuls_counter++;
|
||||
@@ -939,7 +952,7 @@ void handle_pac(unsigned char c1, unsigned char c2, ccx_decoder_608_context *con
|
||||
memset(use_buffer->colors[j], context->settings.default_color, CCX_DECODER_608_SCREEN_WIDTH);
|
||||
memset(use_buffer->fonts[j], FONT_REGULAR, CCX_DECODER_608_SCREEN_WIDTH);
|
||||
use_buffer->characters[j][CCX_DECODER_608_SCREEN_WIDTH] = 0;
|
||||
use_buffer->row_used[j]=0;
|
||||
use_buffer->row_used[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1065,10 +1078,14 @@ int disCommand(unsigned char hi, unsigned char lo, ccx_decoder_608_context *cont
|
||||
/* If wb is NULL, then only XDS will be processed */
|
||||
int process608(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub)
|
||||
{
|
||||
struct ccx_decoder_608_report *report = NULL;
|
||||
static int textprinted = 0;
|
||||
int i;
|
||||
if (context)
|
||||
{
|
||||
report = &context->report;
|
||||
context->bytes_processed_608 += length;
|
||||
}
|
||||
if (!data)
|
||||
{
|
||||
return -1;
|
||||
@@ -1091,7 +1108,8 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
|
||||
if (context == NULL || context->my_field == 2) // Originally: current_field from sequencing.c. Seems to be just to change channel, so context->my_field seems good.
|
||||
ch+=2;
|
||||
|
||||
ccx_decoder_608_report.cc_channels[ch - 1] = 1;
|
||||
if(report)
|
||||
report->cc_channels[ch - 1] = 1;
|
||||
}
|
||||
|
||||
if (hi >= 0x01 && hi <= 0x0E && (context == NULL || context->my_field == 2)) // XDS can only exist in field 2.
|
||||
@@ -1103,8 +1121,8 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
|
||||
ts_start_of_xds=get_fts();
|
||||
in_xds_mode=1;
|
||||
}
|
||||
|
||||
ccx_decoder_608_report.xds=1;
|
||||
if(report)
|
||||
report->xds=1;
|
||||
}
|
||||
if (hi == 0x0F && in_xds_mode && (context == NULL || context->my_field == 2)) // End of XDS block
|
||||
{
|
||||
@@ -1197,7 +1215,7 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
|
||||
context->current_visible_start_ms = get_visible_start();
|
||||
}
|
||||
}
|
||||
if (wrote_to_screen && *context->cc_to_stdout)
|
||||
if (wrote_to_screen && context->cc_to_stdout)
|
||||
fflush (stdout);
|
||||
} // for
|
||||
return i;
|
||||
@@ -6,22 +6,24 @@
|
||||
|
||||
extern LLONG ts_start_of_xds;
|
||||
|
||||
/*
|
||||
/*
|
||||
This variable (ccx_decoder_608_report) holds data on the cc channels & xds packets that are encountered during file parse.
|
||||
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
|
||||
for the report functionality.
|
||||
*/
|
||||
struct ccx_decoder_608_report_t {
|
||||
struct ccx_decoder_608_report
|
||||
{
|
||||
unsigned xds : 1;
|
||||
unsigned cc_channels[4];
|
||||
} ccx_decoder_608_report;
|
||||
};
|
||||
|
||||
typedef struct ccx_decoder_608_settings {
|
||||
typedef struct ccx_decoder_608_settings
|
||||
{
|
||||
int direct_rollup; // Write roll-up captions directly instead of line by line?
|
||||
int force_rollup; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
|
||||
int force_rollup; // 0=Disabled, 1, 2 or 3=max lines in roll-up mode
|
||||
int no_rollup; // If 1, write one line at a time
|
||||
unsigned char default_color; // Default color to use.
|
||||
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
|
||||
int screens_to_process; // How many screenfuls we want? Use -1 for unlimited
|
||||
} ccx_decoder_608_settings;
|
||||
|
||||
typedef struct ccx_decoder_608_context
|
||||
@@ -41,22 +43,25 @@ typedef struct ccx_decoder_608_context
|
||||
int rollup_base_row;
|
||||
LLONG ts_start_of_current_line; /* Time at which the first character for current line was received, =-1 no character received yet */
|
||||
LLONG ts_last_char_received; /* Time at which the last written character was received, =-1 no character received yet */
|
||||
int new_channel; // The new channel after a channel change
|
||||
int new_channel; // The new channel after a channel change
|
||||
int my_field; // Used for sanity checks
|
||||
int my_channel; // Used for sanity checks
|
||||
long bytes_processed_608; // To be written ONLY by process_608
|
||||
struct ccx_s_write *out;
|
||||
int have_cursor_position;
|
||||
int have_cursor_position;
|
||||
|
||||
int trim_subs;
|
||||
enum ccx_encoding_type encoding;
|
||||
|
||||
|
||||
int *halt; // Can be used to halt the feeding of caption data. Set to 1 if screens_to_progress != -1 && screenfuls_counter >= screens_to_process
|
||||
int *cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
|
||||
struct ccx_decoder_608_report report;
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
} ccx_decoder_608_context;
|
||||
|
||||
extern unsigned char *enc_buffer;
|
||||
extern unsigned char str[2048];
|
||||
extern unsigned char str[2048];
|
||||
extern unsigned enc_buffer_used;
|
||||
extern unsigned enc_buffer_capacity;
|
||||
|
||||
@@ -112,10 +117,15 @@ enum command_code
|
||||
};
|
||||
|
||||
|
||||
void ccx_decoder_608_dinit_library(void **ctx);
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
ccx_decoder_608_context ccx_decoder_608_init_library(ccx_decoder_608_settings settings, int channel, int field, int trim_subs, enum ccx_encoding_type encoding, int *halt, int *cc_to_stdout);
|
||||
ccx_decoder_608_context* ccx_decoder_608_init_library(ccx_decoder_608_settings settings, int channel,
|
||||
int field, int trim_subs,
|
||||
enum ccx_encoding_type encoding, int *halt,
|
||||
int cc_to_stdout, LLONG subs_delay,
|
||||
enum ccx_output_format output_format);
|
||||
|
||||
/**
|
||||
* @param data raw cc608 data to be processed
|
||||
@@ -139,11 +149,6 @@ int process608(const unsigned char *data, int length, ccx_decoder_608_context *c
|
||||
void handle_end_of_data(ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
|
||||
int write_cc_buffer(ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
unsigned char *debug_608toASC(unsigned char *ccdata, int channel);
|
||||
|
||||
//void delete_all_lines_but_current(ccx_decoder_608_context *context, struct eia608_screen *data, int row);
|
||||
|
||||
LLONG get_visible_end(void);
|
||||
|
||||
#define __608_H__
|
||||
#endif
|
||||
#endif
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
/* Portions by Daniel Kristjansson, extracted from MythTV's source */
|
||||
|
||||
// #define DEBUG_708_PACKETS // Already working.
|
||||
// #define DEBUG_708_PACKETS // Already working.
|
||||
|
||||
int do_cea708 = 0; // Process 708 data?
|
||||
int cea708services[CCX_DECODERS_708_MAX_SERVICES]; // [] -> 1 for services to be processed
|
||||
int ccx_decoders_708_report = 0;
|
||||
int resets_708;
|
||||
|
||||
struct ccx_decoder_708_report_t ccx_decoder_708_report;
|
||||
static unsigned char current_packet[MAX_708_PACKET_LENGTH]; // Length according to EIA-708B, part 5
|
||||
static int current_packet_length=0;
|
||||
static int last_seq=-1; // -1 -> No last sequence yet
|
||||
@@ -31,27 +33,27 @@ const char *COMMANDS_C0[32]=
|
||||
"BS", // 8 = Backspace
|
||||
NULL, // 9 = Reserved
|
||||
NULL, // A = Reserved
|
||||
NULL, // B = Reserved
|
||||
NULL, // B = Reserved
|
||||
"FF", // C = FF
|
||||
"CR", // D = CR
|
||||
"HCR", // E = HCR
|
||||
NULL, // F = Reserved
|
||||
NULL, // F = Reserved
|
||||
"EXT1",// 0x10 = EXT1,
|
||||
NULL, // 0x11 = Reserved
|
||||
NULL, // 0x12 = Reserved
|
||||
NULL, // 0x13 = Reserved
|
||||
NULL, // 0x14 = Reserved
|
||||
NULL, // 0x15 = Reserved
|
||||
NULL, // 0x11 = Reserved
|
||||
NULL, // 0x12 = Reserved
|
||||
NULL, // 0x13 = Reserved
|
||||
NULL, // 0x14 = Reserved
|
||||
NULL, // 0x15 = Reserved
|
||||
NULL, // 0x16 = Reserved
|
||||
NULL, // 0x17 = Reserved
|
||||
NULL, // 0x17 = Reserved
|
||||
"P16", // 0x18 = P16
|
||||
NULL, // 0x19 = Reserved
|
||||
NULL, // 0x1A = Reserved
|
||||
NULL, // 0x1B = Reserved
|
||||
NULL, // 0x1C = Reserved
|
||||
NULL, // 0x1D = Reserved
|
||||
NULL, // 0x1E = Reserved
|
||||
NULL, // 0x1F = Reserved
|
||||
NULL, // 0x19 = Reserved
|
||||
NULL, // 0x1A = Reserved
|
||||
NULL, // 0x1B = Reserved
|
||||
NULL, // 0x1C = Reserved
|
||||
NULL, // 0x1D = Reserved
|
||||
NULL, // 0x1E = Reserved
|
||||
NULL, // 0x1F = Reserved
|
||||
};
|
||||
|
||||
struct S_COMMANDS_C1 COMMANDS_C1[32]=
|
||||
@@ -71,7 +73,7 @@ struct S_COMMANDS_C1 COMMANDS_C1[32]=
|
||||
{DLW,"DLW","DeleteWindows", 2},
|
||||
{DLY,"DLY","Delay", 2},
|
||||
{DLC,"DLC","DelayCancel", 1},
|
||||
{RST,"RST","Reset", 1},
|
||||
{RST,"RST","Reset", 1},
|
||||
{SPA,"SPA","SetPenAttributes", 3},
|
||||
{SPC,"SPC","SetPenColor", 4},
|
||||
{SPL,"SPL","SetPenLocation", 3},
|
||||
@@ -100,7 +102,7 @@ void clear_packet(void)
|
||||
}
|
||||
|
||||
void cc708_service_reset(cc708_service_decoder *decoder)
|
||||
{
|
||||
{
|
||||
// There's lots of other stuff that we need to do, such as canceling delays
|
||||
for (int j=0;j<8;j++)
|
||||
{
|
||||
@@ -108,8 +110,8 @@ void cc708_service_reset(cc708_service_decoder *decoder)
|
||||
decoder->windows[j].visible=0;
|
||||
decoder->windows[j].memory_reserved=0;
|
||||
decoder->windows[j].is_empty=1;
|
||||
memset (decoder->windows[j].commands, 0,
|
||||
sizeof (decoder->windows[j].commands));
|
||||
memset (decoder->windows[j].commands, 0,
|
||||
sizeof (decoder->windows[j].commands));
|
||||
}
|
||||
decoder->current_window=-1;
|
||||
decoder->current_visible_start_ms=0;
|
||||
@@ -119,16 +121,21 @@ void cc708_service_reset(cc708_service_decoder *decoder)
|
||||
decoder->inited=1;
|
||||
}
|
||||
|
||||
void cc708_reset()
|
||||
void cc708_reset(struct lib_cc_decode *ctx)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, ">>> Entry in cc708_reset()\n");
|
||||
// Clear states of decoders
|
||||
cc708_service_reset(&decoders[0]);
|
||||
cc708_service_reset(&decoders[1]);
|
||||
// Empty packet buffer
|
||||
clear_packet();
|
||||
last_seq=-1;
|
||||
resets_708++;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, ">>> Entry in cc708_reset()\n");
|
||||
|
||||
decoders[0].output_format = ctx->write_format;
|
||||
decoders[1].output_format = ctx->write_format;
|
||||
decoders[0].subs_delay = ctx->subs_delay;
|
||||
decoders[1].subs_delay = ctx->subs_delay;
|
||||
// Clear states of decoders
|
||||
cc708_service_reset(&decoders[0]);
|
||||
cc708_service_reset(&decoders[1]);
|
||||
// Empty packet buffer
|
||||
clear_packet();
|
||||
last_seq=-1;
|
||||
resets_708++;
|
||||
}
|
||||
|
||||
int compWindowsPriorities (const void *a, const void *b)
|
||||
@@ -150,35 +157,35 @@ void clearTV (cc708_service_decoder *decoder, int buffer) // Buffer => 1 or 2
|
||||
|
||||
void printTVtoSRT (cc708_service_decoder *decoder, int which)
|
||||
{
|
||||
if (ccx_decoders_common_settings.output_format == CCX_OF_NULL)
|
||||
if (decoder->output_format == CCX_OF_NULL)
|
||||
return;
|
||||
|
||||
/* tvscreen *tv = (which==1)? &decoder->tv1:&decoder->tv2; */
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
LLONG ms_start= decoder->current_visible_start_ms;
|
||||
LLONG ms_end = get_visible_end() + ccx_decoders_common_settings.subs_delay;
|
||||
LLONG ms_end = get_visible_end() + decoder->subs_delay;
|
||||
int empty=1;
|
||||
ms_start+= ccx_decoders_common_settings.subs_delay;
|
||||
ms_start+= decoder->subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return;
|
||||
|
||||
|
||||
for (int i=0;i<75;i++)
|
||||
{
|
||||
{
|
||||
for (int j=0;j<210;j++)
|
||||
if (decoder->tv->chars[i][j]!=' ')
|
||||
{
|
||||
empty=0;
|
||||
break;
|
||||
}
|
||||
if (!empty)
|
||||
if (!empty)
|
||||
break;
|
||||
}
|
||||
if (empty)
|
||||
return; // Nothing to write
|
||||
if (decoder->fh==-1) // File not yet open, do it now
|
||||
{
|
||||
ccx_common_logging.log_ftn("Creating %s\n", decoder->filename); // originally wbout1.filename, but since line below uses decoder->filename, assume it's good to use?
|
||||
ccx_common_logging.log_ftn("Creating %s\n", decoder->filename); // originally wbout1.filename, but since line below uses decoder->filename, assume it's good to use?
|
||||
decoder->fh= open(decoder->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
|
||||
if (decoder->fh==-1)
|
||||
{
|
||||
@@ -187,13 +194,13 @@ void printTVtoSRT (cc708_service_decoder *decoder, int which)
|
||||
}
|
||||
mstotime (ms_start,&h1,&m1,&s1,&ms1);
|
||||
mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
|
||||
char timeline[128];
|
||||
char timeline[128];
|
||||
decoder->srt_counter++;
|
||||
sprintf (timeline,"%u\r\n",decoder->srt_counter);
|
||||
write (decoder->fh,timeline,strlen (timeline));
|
||||
sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
|
||||
h1,m1,s1,ms1, h2,m2,s2,ms2);
|
||||
write (decoder->fh,timeline,strlen (timeline));
|
||||
write (decoder->fh,timeline,strlen (timeline));
|
||||
for (int i=0;i<75;i++)
|
||||
{
|
||||
int empty=1;
|
||||
@@ -210,7 +217,7 @@ void printTVtoSRT (cc708_service_decoder *decoder, int which)
|
||||
if (decoder->tv->chars[i][l]!=' ')
|
||||
break;
|
||||
for (int j=f;j<=l;j++)
|
||||
write (decoder->fh,&decoder->tv->chars[i][j],1);
|
||||
write (decoder->fh,&decoder->tv->chars[i][j],1);
|
||||
write (decoder->fh,"\r\n",2);
|
||||
}
|
||||
}
|
||||
@@ -283,7 +290,7 @@ void updateScreen (cc708_service_decoder *decoder)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "%d (%d) | ",wnd[i]->number, wnd[i]->priority);
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
for (int i=0;i<visible;i++)
|
||||
{
|
||||
int top,left;
|
||||
@@ -345,13 +352,13 @@ void updateScreen (cc708_service_decoder *decoder)
|
||||
for (int j=0;j<copyrows;j++)
|
||||
{
|
||||
memcpy (decoder->tv->chars[top+j],wnd[i]->rows[j],copycols);
|
||||
}
|
||||
}
|
||||
}
|
||||
decoder->current_visible_start_ms=get_visible_start();
|
||||
}
|
||||
|
||||
/* This function handles future codes. While by definition we can't do any work on them, we must return
|
||||
how many bytes would be consumed if these codes were supported, as defined in the specs.
|
||||
/* This function handles future codes. While by definition we can't do any work on them, we must return
|
||||
how many bytes would be consumed if these codes were supported, as defined in the specs.
|
||||
Note: EXT1 not included */
|
||||
// C2: Extended Miscellaneous Control Codes
|
||||
// TODO: This code is completely untested due to lack of samples. Just following specs!
|
||||
@@ -376,22 +383,22 @@ int handle_708_C3 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
return 6; // ..Six-byte control codes (5 additional byte)
|
||||
// If here, then 90-9F ...
|
||||
|
||||
// These are variable length commands, that can even span several segments
|
||||
// (they allow even downloading fonts or graphics).
|
||||
// These are variable length commands, that can even span several segments
|
||||
// (they allow even downloading fonts or graphics).
|
||||
// TODO: Implemen if a sample ever appears
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_UNSUPPORTED, "This sample contains unsupported 708 data. PLEASE help us improve CCExtractor by submitting it.\n");
|
||||
return 0; // Unreachable, but otherwise there's compilers warnings
|
||||
}
|
||||
|
||||
// This function handles extended codes (EXT1 + code), from the extended sets
|
||||
// G2 (20-7F) => Mostly unmapped, except for a few characters.
|
||||
// G2 (20-7F) => Mostly unmapped, except for a few characters.
|
||||
// G3 (A0-FF) => A0 is the CC symbol, everything else reserved for future expansion in EIA708-B
|
||||
// C2 (00-1F) => Reserved for future extended misc. control and captions command codes
|
||||
// TODO: This code is completely untested due to lack of samples. Just following specs!
|
||||
// Returns number of used bytes, usually 1 (since EXT1 is not counted).
|
||||
// Returns number of used bytes, usually 1 (since EXT1 is not counted).
|
||||
int handle_708_extended_char (cc708_service_decoder *decoder, unsigned char *data, int data_length)
|
||||
{
|
||||
int used;
|
||||
{
|
||||
int used;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "In handle_708_extended_char, first data code: [%c], length: [%u]\n",data[0], data_length);
|
||||
unsigned char c=0x20; // Default to space
|
||||
unsigned char code=data[0];
|
||||
@@ -456,7 +463,7 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
name="Reserved";
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "C0: [%02X] (%d) [%s]\n",data[0],data_length, name);
|
||||
int len=-1;
|
||||
// These commands have a known length even if they are reserved.
|
||||
// These commands have a known length even if they are reserved.
|
||||
if (/* data[0]>=0x00 && */ data[0]<=0xF) // Comment to silence warning
|
||||
{
|
||||
switch (data[0])
|
||||
@@ -465,7 +472,7 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
process_cr (decoder);
|
||||
break;
|
||||
case 0x0e: // HCR (Horizontal Carriage Return)
|
||||
// TODO: Process HDR
|
||||
// TODO: Process HDR
|
||||
break;
|
||||
case 0x0c: // FF (Form Feed)
|
||||
// TODO: Process FF
|
||||
@@ -497,20 +504,20 @@ int handle_708_C0 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "handle_708_C0, command is %d bytes long but we only have %d\n",len, data_length);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// TODO: Do something useful eventually
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void process_character (cc708_service_decoder *decoder, unsigned char internal_char)
|
||||
{
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, ">>> Process_character: %c [%02X] - Window: %d %s, Pen: %d:%d\n", internal_char, internal_char,
|
||||
decoder->current_window,
|
||||
(decoder->windows[decoder->current_window].is_defined?"[OK]":"[undefined]"),
|
||||
decoder->current_window!=-1 ? decoder->windows[decoder->current_window].pen_row:-1,
|
||||
decoder->current_window!=-1 ? decoder->windows[decoder->current_window].pen_column:-1
|
||||
);
|
||||
);
|
||||
if (decoder->current_window==-1 ||
|
||||
!decoder->windows[decoder->current_window].is_defined) // Writing to a non existing window, skipping
|
||||
return;
|
||||
@@ -568,7 +575,7 @@ int handle_708_G1 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
|
||||
/*-------------------------------------------------------
|
||||
WINDOW COMMANDS
|
||||
------------------------------------------------------- */
|
||||
------------------------------------------------------- */
|
||||
void handle_708_CWx_SetCurrentWindow (cc708_service_decoder *decoder, int new_window)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_CWx_SetCurrentWindow, new window: [%d]\n",new_window);
|
||||
@@ -594,17 +601,17 @@ void handle_708_CLW_ClearWindows (cc708_service_decoder *decoder, int windows_bi
|
||||
if (windows_bitmap & 1)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
|
||||
clearWindow (decoder, i);
|
||||
clearWindow (decoder, i);
|
||||
}
|
||||
windows_bitmap>>=1;
|
||||
}
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
}
|
||||
|
||||
void handle_708_DSW_DisplayWindows (cc708_service_decoder *decoder, int windows_bitmap)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DSW_DisplayWindows, windows: ");
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DSW_DisplayWindows, windows: ");
|
||||
if (windows_bitmap==0)
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "None\n");
|
||||
else
|
||||
@@ -619,14 +626,14 @@ void handle_708_DSW_DisplayWindows (cc708_service_decoder *decoder, int windows_
|
||||
{
|
||||
changes=1;
|
||||
decoder->windows[i].visible=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
windows_bitmap>>=1;
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
if (changes)
|
||||
updateScreen (decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_708_HDW_HideWindows (cc708_service_decoder *decoder, int windows_bitmap)
|
||||
@@ -654,7 +661,7 @@ void handle_708_HDW_HideWindows (cc708_service_decoder *decoder, int windows_bit
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
if (changes)
|
||||
updateScreen (decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_708_TGW_ToggleWindows (cc708_service_decoder *decoder, int windows_bitmap)
|
||||
@@ -669,13 +676,13 @@ void handle_708_TGW_ToggleWindows (cc708_service_decoder *decoder, int windows_b
|
||||
if (windows_bitmap & 1)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
|
||||
decoder->windows[i].visible=!decoder->windows[i].visible;
|
||||
decoder->windows[i].visible=!decoder->windows[i].visible;
|
||||
}
|
||||
windows_bitmap>>=1;
|
||||
}
|
||||
updateScreen(decoder);
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
}
|
||||
|
||||
void clearWindowText (e708Window *window)
|
||||
@@ -712,7 +719,7 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
|
||||
int anchor_horizontal = data[3];
|
||||
int row_count = data[4] & 0xf;
|
||||
int anchor_point = data[4]>>4;
|
||||
int col_count = data[5] & 0x3f;
|
||||
int col_count = data[5] & 0x3f;
|
||||
int pen_style = data[6] & 0x7;
|
||||
int win_style = (data[6]>>3) & 0x7;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Priority: [%d] Column lock: [%3s] Row lock: [%3s]\n",
|
||||
@@ -742,7 +749,7 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
|
||||
// If the window is being created, all character positions in the window
|
||||
// are set to the fill color...
|
||||
// TODO: COLORS
|
||||
// ...and the pen location is set to (0,0)
|
||||
// ...and the pen location is set to (0,0)
|
||||
decoder->windows[window].pen_column=0;
|
||||
decoder->windows[window].pen_row=0;
|
||||
if (!decoder->windows[window].memory_reserved)
|
||||
@@ -752,13 +759,13 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
|
||||
decoder->windows[window].rows[i]=(unsigned char *) malloc (I708_MAX_COLUMNS+1);
|
||||
if (decoder->windows[window].rows[i]==NULL) // Great
|
||||
{
|
||||
decoder->windows[window].is_defined=0;
|
||||
decoder->windows[window].is_defined=0;
|
||||
decoder->current_window=-1;
|
||||
for (int j=0;j<i;j++)
|
||||
for (int j=0;j<i;j++)
|
||||
free (decoder->windows[window].rows[j]);
|
||||
return; // TODO: Warn somehow
|
||||
}
|
||||
}
|
||||
}
|
||||
decoder->windows[window].memory_reserved=1;
|
||||
}
|
||||
decoder->windows[window].is_defined=1;
|
||||
@@ -769,7 +776,7 @@ void handle_708_DFx_DefineWindow (cc708_service_decoder *decoder, int window, un
|
||||
// Specs unclear here: Do we need to delete the text in the existing window?
|
||||
// We do this because one of the sample files demands it.
|
||||
// clearWindowText (&decoder->windows[window]);
|
||||
}
|
||||
}
|
||||
// ...also makes the defined windows the current window (setCurrentWindow)
|
||||
handle_708_CWx_SetCurrentWindow (decoder, window);
|
||||
memcpy (decoder->windows[window].commands, data+1, 6);
|
||||
@@ -846,7 +853,7 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
|
||||
{
|
||||
if (windows_bitmap & 1)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "[Window %d] ",i );
|
||||
if (decoder->windows[i].is_defined && decoder->windows[i].visible && !decoder->windows[i].is_empty)
|
||||
changes=1;
|
||||
deleteWindow (decoder, i);
|
||||
@@ -854,7 +861,7 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
|
||||
windows_bitmap>>=1;
|
||||
}
|
||||
}
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "\n");
|
||||
if (changes)
|
||||
updateScreen (decoder);
|
||||
|
||||
@@ -862,7 +869,7 @@ void handle_708_DLW_DeleteWindows (cc708_service_decoder *decoder, int windows_b
|
||||
|
||||
/*-------------------------------------------------------
|
||||
WINDOW COMMANDS
|
||||
------------------------------------------------------- */
|
||||
------------------------------------------------------- */
|
||||
void handle_708_SPA_SetPenAttributes (cc708_service_decoder *decoder, unsigned char *data)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_SPA_SetPenAttributes, attributes: \n");
|
||||
@@ -876,7 +883,7 @@ void handle_708_SPA_SetPenAttributes (cc708_service_decoder *decoder, unsigned c
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Pen size: [%d] Offset: [%d] Text tag: [%d] Font tag: [%d]\n",
|
||||
pen_size, offset, text_tag, font_tag);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Edge type: [%d] Underline: [%d] Italic: [%d]\n",
|
||||
edge_type, underline, italic);
|
||||
edge_type, underline, italic);
|
||||
if (decoder->current_window==-1)
|
||||
{
|
||||
// Can't do anything yet - we need a window to be defined first.
|
||||
@@ -938,7 +945,7 @@ void handle_708_SPL_SetPenLocation (cc708_service_decoder *decoder, unsigned cha
|
||||
|
||||
/*-------------------------------------------------------
|
||||
SYNCHRONIZATION COMMANDS
|
||||
------------------------------------------------------- */
|
||||
------------------------------------------------------- */
|
||||
void handle_708_DLY_Delay (cc708_service_decoder *decoder, int tenths_of_sec)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, " Entry in handle_708_DLY_Delay, delay for [%d] tenths of second.", tenths_of_sec);
|
||||
@@ -958,7 +965,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
struct S_COMMANDS_C1 com=COMMANDS_C1[data[0]-0x80];
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "%s | C1: [%02X] [%s] [%s] (%d)\n",
|
||||
print_mstime(get_fts()),
|
||||
data[0],com.name,com.description, com.length);
|
||||
data[0],com.name,com.description, com.length);
|
||||
if (com.length>data_length)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "C1: Warning: Not enough bytes for command.\n");
|
||||
@@ -977,7 +984,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
handle_708_CWx_SetCurrentWindow (decoder, com.code-CW0); /* Window 0 to 7 */
|
||||
break;
|
||||
case CLW:
|
||||
handle_708_CLW_ClearWindows (decoder, data[1]);
|
||||
handle_708_CLW_ClearWindows (decoder, data[1]);
|
||||
break;
|
||||
case DSW:
|
||||
handle_708_DSW_DisplayWindows (decoder, data[1]);
|
||||
@@ -1008,7 +1015,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
break;
|
||||
case SPL:
|
||||
handle_708_SPL_SetPenLocation (decoder, data);
|
||||
break;
|
||||
break;
|
||||
case RSV93:
|
||||
case RSV94:
|
||||
case RSV95:
|
||||
@@ -1017,7 +1024,7 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
break;
|
||||
case SWA:
|
||||
handle_708_SWA_SetWindowAttributes (decoder, data);
|
||||
break;
|
||||
break;
|
||||
case DF0:
|
||||
case DF1:
|
||||
case DF2:
|
||||
@@ -1027,23 +1034,23 @@ int handle_708_C1 (cc708_service_decoder *decoder, unsigned char *data, int data
|
||||
case DF6:
|
||||
case DF7:
|
||||
handle_708_DFx_DefineWindow (decoder, com.code-DF0, data); /* Window 0 to 7 */
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
ccx_common_logging.log_ftn ("BUG: Unhandled code in handle_708_C1.\n");
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return com.length;
|
||||
}
|
||||
|
||||
|
||||
void process_service_block (cc708_service_decoder *decoder, unsigned char *data, int data_length)
|
||||
{
|
||||
int i=0;
|
||||
int i=0;
|
||||
while (i<data_length)
|
||||
{
|
||||
int used=-1;
|
||||
if (data[i]!=EXT1)
|
||||
if (data[i]!=EXT1)
|
||||
{
|
||||
// Group C0
|
||||
if (/* data[i]>=0x00 && */ data[i]<=0x1F) // Comment to silence warning
|
||||
@@ -1068,20 +1075,20 @@ void process_service_block (cc708_service_decoder *decoder, unsigned char *data,
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "There was a problem handling the data. Reseting service decoder\n");
|
||||
// TODO: Not sure if a local reset is going to be helpful here.
|
||||
cc708_service_reset (decoder);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else // Use extended set
|
||||
{
|
||||
{
|
||||
used=handle_708_extended_char (decoder, data+i+1,data_length-1);
|
||||
used++; // Since we had EXT1
|
||||
used++; // Since we had EXT1
|
||||
}
|
||||
i+=used;
|
||||
i+=used;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_current_packet (void)
|
||||
void process_current_packet (struct lib_cc_decode* ctx)
|
||||
{
|
||||
int seq=(current_packet[0] & 0xC0) >> 6; // Two most significants bits
|
||||
int len=current_packet[0] & 0x3F; // 6 least significants bits
|
||||
@@ -1091,31 +1098,31 @@ void process_current_packet (void)
|
||||
if (current_packet_length==0)
|
||||
return;
|
||||
if (len==0) // This is well defined in EIA-708; no magic.
|
||||
len=128;
|
||||
len=128;
|
||||
else
|
||||
len=len*2;
|
||||
// Note that len here is the length including the header
|
||||
#ifdef DEBUG_708_PACKETS
|
||||
#ifdef DEBUG_708_PACKETS
|
||||
ccx_common_logging.log_ftn ("Sequence: %d, packet length: %d\n",seq,len);
|
||||
#endif
|
||||
if (current_packet_length!=len) // Is this possible?
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Packet length mismatch (%s%d), first two data bytes %02X %02X, current picture:%s\n",
|
||||
current_packet_length-len>0?"+":"", current_packet_length-len,
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Packet length mismatch (%s%d), first two data bytes %02X %02X, current picture:%s\n",
|
||||
current_packet_length-len>0?"+":"", current_packet_length-len,
|
||||
current_packet[0], current_packet[1], pict_types[current_picture_coding_type]);
|
||||
cc708_reset();
|
||||
cc708_reset(ctx);
|
||||
return;
|
||||
}
|
||||
if (last_seq!=-1 && (last_seq+1)%4!=seq)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Unexpected sequence number, it was [%d] but should have been [%d]\n",
|
||||
seq,(last_seq+1)%4);
|
||||
cc708_reset();
|
||||
cc708_reset(ctx);
|
||||
return;
|
||||
}
|
||||
last_seq=seq;
|
||||
|
||||
unsigned char *pos=current_packet+1;
|
||||
|
||||
unsigned char *pos=current_packet+1;
|
||||
|
||||
while (pos<current_packet+len)
|
||||
{
|
||||
@@ -1123,25 +1130,25 @@ void process_current_packet (void)
|
||||
int block_length = (pos[0] & 0x1F); // 5 less significant bits
|
||||
|
||||
ccx_common_logging.debug_ftn (CCX_DMT_708, "Standard header: Service number: [%d] Block length: [%d]\n",service_number,
|
||||
block_length);
|
||||
block_length);
|
||||
|
||||
if (service_number==7) // There is an extended header
|
||||
{
|
||||
pos++;
|
||||
pos++;
|
||||
service_number=(pos[0] & 0x3F); // 6 more significant bits
|
||||
// printf ("Extended header: Service number: [%d]\n",service_number);
|
||||
if (service_number<7)
|
||||
if (service_number<7)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Illegal service number in extended header: [%d]\n",service_number);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (service_number==0 && block_length==0) // Null header already?
|
||||
{
|
||||
if (pos!=(current_packet+len-1)) // i.e. last byte in packet
|
||||
{
|
||||
// Not sure if this is correct
|
||||
printf ("Null header before it was expected.\n");
|
||||
printf ("Null header before it was expected.\n");
|
||||
// break;
|
||||
}
|
||||
} */
|
||||
@@ -1159,8 +1166,8 @@ void process_current_packet (void)
|
||||
|
||||
if (service_number>0 && decoders[service_number-1].inited)
|
||||
process_service_block (&decoders[service_number-1], pos, block_length);
|
||||
|
||||
pos+=block_length; // Skip data
|
||||
|
||||
pos+=block_length; // Skip data
|
||||
}
|
||||
|
||||
clear_packet();
|
||||
@@ -1168,38 +1175,38 @@ void process_current_packet (void)
|
||||
if (pos!=current_packet+len) // For some reason we didn't parse the whole packet
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "There was a problem with this packet, reseting\n");
|
||||
cc708_reset();
|
||||
cc708_reset(ctx);
|
||||
}
|
||||
|
||||
if (len<128 && *pos) // Null header is mandatory if there is room
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Null header expected but not found.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_708 (const unsigned char *data, int datalength)
|
||||
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength)
|
||||
{
|
||||
/* Note: The data has this format:
|
||||
1 byte for cc_valid
|
||||
/* Note: The data has this format:
|
||||
1 byte for cc_valid
|
||||
1 byte for cc_type
|
||||
2 bytes for the actual data */
|
||||
if (!do_cea708 && !ccx_decoders_708_report)
|
||||
return;
|
||||
|
||||
|
||||
for (int i=0;i<datalength;i+=4)
|
||||
{
|
||||
unsigned char cc_valid=data[i];
|
||||
unsigned char cc_type=data[i+1];
|
||||
unsigned char cc_type=data[i+1];
|
||||
|
||||
switch (cc_type)
|
||||
{
|
||||
case 2:
|
||||
case 2:
|
||||
ccx_common_logging.debug_ftn (CCX_DMT_708, "708: DTVCC Channel Packet Data\n");
|
||||
if (cc_valid==0) // This ends the previous packet
|
||||
process_current_packet();
|
||||
process_current_packet(ctx);
|
||||
else
|
||||
{
|
||||
if (current_packet_length>253)
|
||||
if (current_packet_length>253)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
|
||||
}
|
||||
@@ -1210,12 +1217,12 @@ void do_708 (const unsigned char *data, int datalength)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 3:
|
||||
ccx_common_logging.debug_ftn (CCX_DMT_708, "708: DTVCC Channel Packet Start\n");
|
||||
process_current_packet();
|
||||
process_current_packet(ctx);
|
||||
if (cc_valid)
|
||||
{
|
||||
if (current_packet_length>127)
|
||||
if (current_packet_length>127)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_708, "Warning: Legal packet size exceeded, data not added.\n");
|
||||
}
|
||||
@@ -1226,7 +1233,7 @@ void do_708 (const unsigned char *data, int datalength)
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
ccx_common_logging.fatal_ftn (CCX_COMMON_EXIT_BUG_BUG, "708: shouldn't be here - cc_type: %d\n", cc_type);
|
||||
}
|
||||
}
|
||||
@@ -1241,11 +1248,11 @@ void ccx_decoders_708_init_library(char *basefilename,const char *extension,int
|
||||
cc708_service_reset (&decoders[i]);
|
||||
if (decoders[i].filename==NULL)
|
||||
{
|
||||
decoders[i].filename = (char *) malloc (strlen (basefilename)+4+strlen (extension));
|
||||
sprintf (decoders[i].filename, "%s_%d%s", basefilename,i+1,extension);
|
||||
}
|
||||
decoders[i].filename = (char *) malloc (strlen (basefilename)+4+strlen (extension));
|
||||
sprintf (decoders[i].filename, "%s_%d%s", basefilename,i+1,extension);
|
||||
}
|
||||
decoders[i].fh=-1;
|
||||
decoders[i].srt_counter=0;
|
||||
}
|
||||
}
|
||||
ccx_decoders_708_report = report;
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
#define CCX_DECODERS_708_MAX_SERVICES 63
|
||||
|
||||
#define I708_MAX_ROWS 15
|
||||
#define I708_MAX_COLUMNS 42
|
||||
#define I708_MAX_COLUMNS 42
|
||||
|
||||
#define I708_SCREENGRID_ROWS 75
|
||||
#define I708_SCREENGRID_COLUMNS 210
|
||||
@@ -20,9 +20,11 @@ This variable (ccx_decoder_708_report) holds data on the cc channels & xds packe
|
||||
This can be interesting if you just want to know what kind of data a file holds that has 608 packets. CCExtractor uses it
|
||||
for the report functionality.
|
||||
*/
|
||||
struct ccx_decoder_708_report_t {
|
||||
struct ccx_decoder_708_report_t
|
||||
{
|
||||
unsigned services[CCX_DECODERS_708_MAX_SERVICES];
|
||||
} ccx_decoder_708_report;
|
||||
};
|
||||
extern struct ccx_decoder_708_report_t ccx_decoder_708_report;
|
||||
|
||||
enum COMMANDS_C0_CODES
|
||||
{
|
||||
@@ -54,7 +56,7 @@ enum COMMANDS_C1_CODES
|
||||
DLY=0x8D,
|
||||
DLC=0x8E,
|
||||
RST=0x8F,
|
||||
SPA=0x90,
|
||||
SPA=0x90,
|
||||
SPC=0x91,
|
||||
SPL=0x92,
|
||||
RSV93=0x93,
|
||||
@@ -273,7 +275,7 @@ typedef struct e708Window
|
||||
typedef struct tvscreen
|
||||
{
|
||||
unsigned char chars[I708_SCREENGRID_ROWS][I708_SCREENGRID_COLUMNS+1];
|
||||
}
|
||||
}
|
||||
tvscreen;
|
||||
|
||||
typedef struct cc708_service_decoder
|
||||
@@ -289,6 +291,8 @@ typedef struct cc708_service_decoder
|
||||
char *filename; // Where we are going to write our output
|
||||
int fh; // Handle to output file. -1 if not yet open
|
||||
int srt_counter;
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
}
|
||||
cc708_service_decoder;
|
||||
|
||||
@@ -297,7 +301,7 @@ extern int cea708services[]; // [] -> 1 for services to be processed
|
||||
|
||||
extern int resets_708;
|
||||
|
||||
void do_708 (const unsigned char *data, int datalength);
|
||||
void do_708 (struct lib_cc_decode* ctx, const unsigned char *data, int datalength);
|
||||
|
||||
unsigned char get_internal_from_G0 (unsigned char g0_char);
|
||||
unsigned char get_internal_from_G1 (unsigned char g1_char);
|
||||
@@ -306,4 +310,4 @@ unsigned char get_internal_from_G3 (unsigned char g3_char);
|
||||
void process_character (cc708_service_decoder *decoder, unsigned char internal_char);
|
||||
|
||||
void ccx_decoders_708_init_library(char *basefilename,const char *extension, int report);
|
||||
#endif
|
||||
#endif
|
||||
319
src/lib_ccx/ccx_decoders_common.c
Normal file
319
src/lib_ccx/ccx_decoders_common.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/* Functions used by both the 608 and 708 decoders. An effort should be
|
||||
made to reuse, not duplicate, as many functions as possible */
|
||||
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_common_char_encoding.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "lib_ccx.h"
|
||||
|
||||
|
||||
uint64_t utc_refvalue = UINT64_MAX; /* _UI64_MAX means don't use UNIX, 0 = use current system time as reference, +1 use a specific reference */
|
||||
extern int in_xds_mode;
|
||||
|
||||
// Preencoded strings
|
||||
unsigned char encoded_crlf[16];
|
||||
unsigned int encoded_crlf_length;
|
||||
unsigned char encoded_br[16];
|
||||
unsigned int encoded_br_length;
|
||||
|
||||
LLONG minimum_fts = 0; // No screen should start before this FTS
|
||||
|
||||
/* This function returns a FTS that is guaranteed to be at least 1 ms later than the end of the previous screen. It shouldn't be needed
|
||||
obviously but it guarantees there's no timing overlap */
|
||||
LLONG get_visible_start (void)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts <= minimum_fts)
|
||||
fts = minimum_fts+1;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible Start time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
|
||||
/* This function returns the current FTS and saves it so it can be used by get_visible_start */
|
||||
LLONG get_visible_end (void)
|
||||
{
|
||||
LLONG fts = get_fts();
|
||||
if (fts>minimum_fts)
|
||||
minimum_fts=fts;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_608, "Visible End time=%s\n", print_mstime(fts));
|
||||
return fts;
|
||||
}
|
||||
|
||||
void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_non_blank)
|
||||
{
|
||||
*last_non_blank = -1;
|
||||
*first_non_blank = -1;
|
||||
for (int i = 0; i<CCX_DECODER_608_SCREEN_WIDTH; i++)
|
||||
{
|
||||
unsigned char c = line[i];
|
||||
if (c != ' ' && c != 0x89)
|
||||
{
|
||||
if (*first_non_blank == -1)
|
||||
*first_non_blank = i;
|
||||
*last_non_blank = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding)
|
||||
{
|
||||
unsigned char *line = data->characters[line_num];
|
||||
int last_non_blank = -1;
|
||||
int first_non_blank = -1;
|
||||
unsigned char *orig = buffer; // Keep for debugging
|
||||
find_limit_characters(line, &first_non_blank, &last_non_blank);
|
||||
if (!trim_subs)
|
||||
first_non_blank = 0;
|
||||
|
||||
if (first_non_blank == -1)
|
||||
{
|
||||
*buffer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytes = 0;
|
||||
for (int i = first_non_blank; i <= last_non_blank; i++)
|
||||
{
|
||||
char c = line[i];
|
||||
switch (encoding)
|
||||
{
|
||||
case CCX_ENC_UTF_8:
|
||||
bytes = get_char_in_utf_8(buffer, c);
|
||||
break;
|
||||
case CCX_ENC_LATIN_1:
|
||||
get_char_in_latin_1(buffer, c);
|
||||
bytes = 1;
|
||||
break;
|
||||
case CCX_ENC_UNICODE:
|
||||
get_char_in_unicode(buffer, c);
|
||||
bytes = 2;
|
||||
break;
|
||||
}
|
||||
buffer += bytes;
|
||||
}
|
||||
*buffer = 0;
|
||||
return (unsigned)(buffer - orig); // Return length
|
||||
}
|
||||
|
||||
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub)
|
||||
{
|
||||
int ret = -1;
|
||||
for (int j = 0; j < cc_count * 3; j = j + 3)
|
||||
{
|
||||
if (validate_cc_data_pair( cc_data + j ) )
|
||||
continue;
|
||||
ret = do_cb(ctx, cc_data + j, sub);
|
||||
if (ret == 1) //1 means success here
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int validate_cc_data_pair (unsigned char *cc_data_pair)
|
||||
{
|
||||
unsigned char cc_valid = (*cc_data_pair & 4) >>2;
|
||||
unsigned char cc_type = *cc_data_pair & 3;
|
||||
|
||||
if (!cc_valid)
|
||||
return -1;
|
||||
|
||||
if (cc_type==0 || cc_type==1)
|
||||
{
|
||||
// For EIA-608 data we verify parity.
|
||||
if (!cc608_parity_table[cc_data_pair[2]])
|
||||
{
|
||||
// If the second byte doesn't pass parity, ignore pair
|
||||
return -1;
|
||||
}
|
||||
if (!cc608_parity_table[cc_data_pair[1]])
|
||||
{
|
||||
// The first byte doesn't pass parity, we replace it with a solid blank
|
||||
// and process the pair.
|
||||
cc_data_pair[1]=0x7F;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char cc_valid = (*cc_block & 4) >>2;
|
||||
unsigned char cc_type = *cc_block & 3;
|
||||
|
||||
int timeok = 1;
|
||||
|
||||
if ( ctx->fix_padding
|
||||
&& cc_valid==0 && cc_type <= 1 // Only fix NTSC packets
|
||||
&& cc_block[1]==0 && cc_block[2]==0 )
|
||||
{
|
||||
/* Padding */
|
||||
cc_valid=1;
|
||||
cc_block[1]=0x80;
|
||||
cc_block[2]=0x80;
|
||||
}
|
||||
|
||||
if ( ctx->write_format!=CCX_OF_RAW && // In raw we cannot skip padding because timing depends on it
|
||||
ctx->write_format!=CCX_OF_DVDRAW &&
|
||||
(cc_block[0]==0xFA || cc_block[0]==0xFC || cc_block[0]==0xFD )
|
||||
&& (cc_block[1]&0x7F)==0 && (cc_block[2]&0x7F)==0) // CFS: Skip non-data, makes debugging harder.
|
||||
return 1;
|
||||
|
||||
// Print raw data with FTS.
|
||||
dbg_print(CCX_DMT_CBRAW, "%s %d %02X:%c%c:%02X", print_mstime(fts_now + fts_global),in_xds_mode,
|
||||
cc_block[0], cc_block[1]&0x7f,cc_block[2]&0x7f, cc_block[2]);
|
||||
|
||||
/* In theory the writercwtdata() function could return early and not
|
||||
* go through the 608/708 cases below. We do that to get accurate
|
||||
* counts for cb_field1, cb_field2 and cb_708.
|
||||
* Note that printdata() and do_708() must not be called for
|
||||
* the CCX_OF_RCWT case. */
|
||||
|
||||
if (cc_valid || cc_type==3)
|
||||
{
|
||||
ctx->cc_stats[cc_type]++;
|
||||
|
||||
switch (cc_type)
|
||||
{
|
||||
case 0:
|
||||
dbg_print(CCX_DMT_CBRAW, " %s .. ..\n", debug_608toASC( cc_block, 0));
|
||||
|
||||
current_field=1;
|
||||
ctx->saw_caption_block = 1;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts() < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts() > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
}
|
||||
if (timeok)
|
||||
{
|
||||
if(ctx->write_format!=CCX_OF_RCWT)
|
||||
printdata (ctx, cc_block+1,2,0,0, sub);
|
||||
else
|
||||
writercwtdata(ctx, cc_block);
|
||||
}
|
||||
cb_field1++;
|
||||
break;
|
||||
case 1:
|
||||
dbg_print(CCX_DMT_CBRAW, " .. %s ..\n", debug_608toASC( cc_block, 1));
|
||||
|
||||
current_field=2;
|
||||
ctx->saw_caption_block = 1;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts() < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts() > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
}
|
||||
if (timeok)
|
||||
{
|
||||
if(ctx->write_format!=CCX_OF_RCWT)
|
||||
printdata (ctx, 0,0,cc_block+1,2, sub);
|
||||
else
|
||||
writercwtdata(ctx, cc_block);
|
||||
}
|
||||
cb_field2++;
|
||||
break;
|
||||
case 2: //EIA-708
|
||||
// DTVCC packet data
|
||||
// Fall through
|
||||
case 3: //EIA-708
|
||||
dbg_print(CCX_DMT_CBRAW, " .. .. DD\n");
|
||||
|
||||
// DTVCC packet start
|
||||
current_field=3;
|
||||
|
||||
if (ctx->extraction_start.set &&
|
||||
get_fts() < ctx->extraction_start.time_in_ms)
|
||||
timeok = 0;
|
||||
if (ctx->extraction_end.set &&
|
||||
get_fts() > ctx->extraction_end.time_in_ms)
|
||||
{
|
||||
timeok = 0;
|
||||
ctx->processed_enough=1;
|
||||
}
|
||||
char temp[4];
|
||||
temp[0]=cc_valid;
|
||||
temp[1]=cc_type;
|
||||
temp[2]=cc_block[1];
|
||||
temp[3]=cc_block[2];
|
||||
if (timeok)
|
||||
{
|
||||
if(ctx->write_format!=CCX_OF_RCWT)
|
||||
do_708 (ctx,(const unsigned char *) temp, 4);
|
||||
else
|
||||
writercwtdata(ctx, cc_block);
|
||||
}
|
||||
cb_708++;
|
||||
// Check for bytes read
|
||||
// printf ("Warning: Losing EIA-708 data!\n");
|
||||
break;
|
||||
default:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!");
|
||||
} // switch (cc_type)
|
||||
} // cc_valid
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_CBRAW, " .. .. ..\n");
|
||||
dbg_print(CCX_DMT_VERBOSE, "Found !(cc_valid || cc_type==3) - ignore this block\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting)
|
||||
{
|
||||
struct lib_cc_decode *ctx = NULL;
|
||||
|
||||
ctx = malloc(sizeof(struct lib_cc_decode));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
// Prepare 608 context
|
||||
ctx->context_cc608_field_1 = ccx_decoder_608_init_library(
|
||||
ccx_options.settings_608,
|
||||
ccx_options.cc_channel,
|
||||
1,
|
||||
ccx_options.trim_subs,
|
||||
ccx_options.encoding,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->subs_delay,
|
||||
setting->output_format
|
||||
);
|
||||
ctx->context_cc608_field_2 = ccx_decoder_608_init_library(
|
||||
ccx_options.settings_608,
|
||||
ccx_options.cc_channel,
|
||||
2,
|
||||
ccx_options.trim_subs,
|
||||
ccx_options.encoding,
|
||||
&ctx->processed_enough,
|
||||
setting->cc_to_stdout,
|
||||
setting->subs_delay,
|
||||
setting->output_format
|
||||
);
|
||||
|
||||
ctx->fix_padding = setting->fix_padding;
|
||||
ctx->write_format = setting->output_format;
|
||||
ctx->subs_delay = setting->subs_delay;
|
||||
ctx->wbout1 = setting->wbout1;
|
||||
memcpy(&ctx->extraction_start, &setting->extraction_start,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&ctx->extraction_end, &setting->extraction_end,sizeof(struct ccx_boundary_time));
|
||||
return ctx;
|
||||
}
|
||||
void dinit_cc_decode(struct lib_cc_decode **ctx)
|
||||
{
|
||||
struct lib_cc_decode *lctx = *ctx;
|
||||
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1);
|
||||
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2);
|
||||
freep(ctx);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_decoders_structs.h"
|
||||
|
||||
extern unsigned char encoded_crlf[16]; // We keep it encoded here so we don't have to do it many times
|
||||
@@ -22,4 +23,12 @@ void find_limit_characters(unsigned char *line, int *first_non_blank, int *last_
|
||||
unsigned get_decoder_line_basic(unsigned char *buffer, int line_num, struct eia608_screen *data, int trim_subs, enum ccx_encoding_type encoding);
|
||||
|
||||
void ccx_decoders_common_settings_init(LLONG subs_delay, enum ccx_output_format output_format);
|
||||
|
||||
int validate_cc_data_pair (unsigned char *cc_data_pair);
|
||||
int process_cc_data (struct lib_cc_decode *ctx, unsigned char *cc_data, int cc_count, struct cc_subtitle *sub);
|
||||
int do_cb (struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle *sub);
|
||||
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
|
||||
const unsigned char *data2, int length2, struct cc_subtitle *sub);
|
||||
struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting);
|
||||
void dinit_cc_decode(struct lib_cc_decode **ctx);
|
||||
#endif
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef CCX_DECODERS_STRUCTS_H
|
||||
#define CCX_DECODERS_STRUCTS_H
|
||||
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_timing.h"
|
||||
|
||||
// Define max width in characters/columns on the screen
|
||||
#define CCX_DECODER_608_SCREEN_WIDTH 32
|
||||
@@ -17,6 +19,9 @@ struct cc_bitmap
|
||||
int nb_colors;
|
||||
unsigned char *data[2];
|
||||
int linesize[2];
|
||||
#ifdef ENABLE_OCR
|
||||
char *ocr_text;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum ccx_eia608_format
|
||||
@@ -70,10 +75,31 @@ typedef struct eia608_screen // A CC buffer
|
||||
int cur_xds_packet_class;
|
||||
} eia608_screen;
|
||||
|
||||
struct ccx_decoderrs_common_settings_t {
|
||||
struct ccx_decoders_common_settings_t
|
||||
{
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
} ccx_decoders_common_settings;
|
||||
enum ccx_output_format output_format; // What kind of output format should be used?
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
void *wbout1;
|
||||
int cc_to_stdout;
|
||||
};
|
||||
struct lib_cc_decode
|
||||
{
|
||||
int cc_stats[4];
|
||||
int saw_caption_block;
|
||||
int processed_enough; // If 1, we have enough lines, time, etc.
|
||||
|
||||
#define CCX_DECODERS_STRUCTS_H
|
||||
#endif
|
||||
/* 608 contexts - note that this shouldn't be global, they should be
|
||||
per program */
|
||||
void *context_cc608_field_1;
|
||||
void *context_cc608_field_2;
|
||||
|
||||
int fix_padding; // Replace 0000 with 8080 in HDTV (needed for some cards)
|
||||
enum ccx_output_format write_format; // 0=Raw, 1=srt, 2=SMI
|
||||
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
|
||||
void *wbout1;
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,8 +20,8 @@ static int xds_start_time_shown=0;
|
||||
static int xds_program_length_shown=0;
|
||||
static char xds_program_description[8][33];
|
||||
|
||||
static char current_xds_network_name[33];
|
||||
static char current_xds_program_name[33];
|
||||
static char current_xds_network_name[33];
|
||||
static char current_xds_program_name[33];
|
||||
static char current_xds_call_letters[7];
|
||||
static char current_xds_program_type[33];
|
||||
|
||||
@@ -101,12 +101,12 @@ static const char *XDSProgramTypes[]=
|
||||
#define XDS_TYPE_PROGRAM_DESC_8 0x17
|
||||
|
||||
// Types for the class channel
|
||||
#define XDS_TYPE_NETWORK_NAME 1
|
||||
#define XDS_TYPE_CALL_LETTERS_AND_CHANNEL 2
|
||||
#define XDS_TYPE_NETWORK_NAME 1
|
||||
#define XDS_TYPE_CALL_LETTERS_AND_CHANNEL 2
|
||||
#define XDS_TYPE_TSID 4 // Transmission Signal Identifier
|
||||
|
||||
// Types for miscellaneous packets
|
||||
#define XDS_TYPE_TIME_OF_DAY 1
|
||||
#define XDS_TYPE_TIME_OF_DAY 1
|
||||
#define XDS_TYPE_LOCAL_TIME_ZONE 4
|
||||
#define XDS_TYPE_OUT_OF_BAND_CHANNEL_NUMBER 0x40
|
||||
|
||||
@@ -120,7 +120,7 @@ struct xds_buffer
|
||||
int xds_type;
|
||||
unsigned char bytes[NUM_BYTES_PER_PACKET]; // Class + type (repeated for convenience) + data + zero
|
||||
unsigned char used_bytes;
|
||||
} xds_buffers[NUM_XDS_BUFFERS];
|
||||
} xds_buffers[NUM_XDS_BUFFERS];
|
||||
|
||||
static int cur_xds_buffer_idx=-1;
|
||||
static int cur_xds_packet_class=-1;
|
||||
@@ -196,7 +196,7 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time,
|
||||
if (!wb || wb->fh==-1)
|
||||
return;
|
||||
|
||||
if (start_time == -1)
|
||||
if (start_time == -1)
|
||||
{
|
||||
// Means we entered XDS mode without making a note of the XDS start time. This is a bug.
|
||||
ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Bug in timedtranscript (XDS). Please report.");
|
||||
@@ -254,7 +254,7 @@ void xds_write_transcript_line_prefix (struct ccx_s_write *wb, LLONG start_time,
|
||||
|
||||
if (ccx_decoders_xds_context.transcriptFormat.showCC){
|
||||
fdprintf(wb->fh, "%s|", XDSclasses_short[cur_xds_packet_class]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void xdsprint (struct cc_subtitle *sub,const char *fmt,...)
|
||||
{
|
||||
@@ -283,14 +283,14 @@ void xdsprint (struct cc_subtitle *sub,const char *fmt,...)
|
||||
size = n+1; /* precisely what is needed */
|
||||
else /* glibc 2.0 */
|
||||
size *= 2; /* twice the old size */
|
||||
if ((np = (char *) realloc (p, size)) == NULL)
|
||||
if ((np = (char *) realloc (p, size)) == NULL)
|
||||
{
|
||||
free(p);
|
||||
return ;
|
||||
} else {
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xds_debug_test(struct cc_subtitle *sub)
|
||||
@@ -336,7 +336,7 @@ void clear_xds_buffer (int num)
|
||||
}
|
||||
|
||||
void process_xds_bytes (const unsigned char hi, int lo)
|
||||
{
|
||||
{
|
||||
int is_new;
|
||||
if (hi>=0x01 && hi<=0x0f)
|
||||
{
|
||||
@@ -347,7 +347,7 @@ void process_xds_bytes (const unsigned char hi, int lo)
|
||||
int matching_buf=-1;
|
||||
for (int i=0;i<NUM_XDS_BUFFERS;i++)
|
||||
{
|
||||
if (xds_buffers[i].in_use &&
|
||||
if (xds_buffers[i].in_use &&
|
||||
xds_buffers[i].xds_class==xds_class &&
|
||||
xds_buffers[i].xds_type==lo)
|
||||
{
|
||||
@@ -357,7 +357,7 @@ void process_xds_bytes (const unsigned char hi, int lo)
|
||||
if (first_free_buf==-1 && !xds_buffers[i].in_use)
|
||||
first_free_buf=i;
|
||||
}
|
||||
/* Here, 3 possibilities:
|
||||
/* Here, 3 possibilities:
|
||||
1) We already had a buffer for this class/type and matching_buf points to it
|
||||
2) We didn't have a buffer for this class/type and first_free_buf points to an unused one
|
||||
3) All buffers are full and we will have to skip this packet.
|
||||
@@ -378,7 +378,7 @@ void process_xds_bytes (const unsigned char hi, int lo)
|
||||
xds_buffers[cur_xds_buffer_idx].xds_type=lo;
|
||||
xds_buffers[cur_xds_buffer_idx].used_bytes=0;
|
||||
xds_buffers[cur_xds_buffer_idx].in_use=1;
|
||||
memset (xds_buffers[cur_xds_buffer_idx].bytes,0,NUM_BYTES_PER_PACKET);
|
||||
memset (xds_buffers[cur_xds_buffer_idx].bytes,0,NUM_BYTES_PER_PACKET);
|
||||
}
|
||||
if (!is_new)
|
||||
{
|
||||
@@ -401,17 +401,17 @@ void process_xds_bytes (const unsigned char hi, int lo)
|
||||
// Should always happen
|
||||
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes++]=hi;
|
||||
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes++]=lo;
|
||||
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes]=0;
|
||||
xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes]=0;
|
||||
}
|
||||
}
|
||||
|
||||
void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
{
|
||||
static unsigned last_c1=-1, last_c2=-1;
|
||||
static char copy_permited[256];
|
||||
static char copy_permited[256];
|
||||
static char aps[256];
|
||||
static char rcd[256];
|
||||
int changed=0;
|
||||
int changed=0;
|
||||
unsigned c1_6=(c1&0x40)>>6;
|
||||
/* unsigned unused1=(c1&0x20)>>5; */
|
||||
unsigned cgms_a_b4=(c1&0x10)>>4;
|
||||
@@ -431,11 +431,11 @@ void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned
|
||||
if (last_c1!=c1 || last_c2!=c2)
|
||||
{
|
||||
changed=1;
|
||||
last_c1=c1;
|
||||
last_c2=c2;
|
||||
last_c1=c1;
|
||||
last_c2=c2;
|
||||
// Changed since last time, decode
|
||||
|
||||
const char *copytext[4]={"Copy permited (no restrictions)", "No more copies (one generation copy has been made)",
|
||||
const char *copytext[4]={"Copy permited (no restrictions)", "No more copies (one generation copy has been made)",
|
||||
"One generation of copies can be made", "No copying is permited"};
|
||||
const char *apstext[4]={"No APS", "PSP On; Split Burst Off", "PSP On; 2 line Split Burst On", "PSP On; 4 line Split Burst On"};
|
||||
sprintf (copy_permited,"CGMS: %s", copytext[cgms_a_b4*2+cgms_a_b3]);
|
||||
@@ -450,7 +450,7 @@ void xds_do_copy_generation_management_system (struct cc_subtitle *sub, unsigned
|
||||
xdsprint(sub, aps);
|
||||
xdsprint(sub, rcd);
|
||||
}
|
||||
if (changed)
|
||||
if (changed)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n",copy_permited);
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n",aps);
|
||||
@@ -489,14 +489,14 @@ void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
if (last_c1!=c1 || last_c2!=c2)
|
||||
{
|
||||
changed=1;
|
||||
last_c1=c1;
|
||||
last_c2=c2;
|
||||
last_c1=c1;
|
||||
last_c2=c2;
|
||||
// Changed since last time, decode
|
||||
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
|
||||
if (!a1 && a0) // US TV parental guidelines
|
||||
{
|
||||
const char *agetext[8]={"None", "TV-Y (All Children)", "TV-Y7 (Older Children)",
|
||||
"TV-G (General Audience)", "TV-PG (Parental Guidance Suggested)",
|
||||
const char *agetext[8]={"None", "TV-Y (All Children)", "TV-Y7 (Older Children)",
|
||||
"TV-G (General Audience)", "TV-PG (Parental Guidance Suggested)",
|
||||
"TV-14 (Parents Strongly Cautioned)", "TV-MA (Mature Audience Only)", "None"};
|
||||
sprintf (age,"ContentAdvisory: US TV Parental Guidelines. Age Rating: %s", agetext[g2*4+g1*2+g0]);
|
||||
content[0]=0;
|
||||
@@ -526,8 +526,8 @@ void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
}
|
||||
if (a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
|
||||
{
|
||||
const char *ratingtext[8]={"Exempt", "Children", "Children eight years and older",
|
||||
"General programming suitable for all audiences", "Parental Guidance",
|
||||
const char *ratingtext[8]={"Exempt", "Children", "Children eight years and older",
|
||||
"General programming suitable for all audiences", "Parental Guidance",
|
||||
"Viewers 14 years and older", "Adult Programming", "[undefined]"};
|
||||
sprintf (rating,"ContentAdvisory: Canadian English Rating: %s", ratingtext[g2*4+g1*2+g0]);
|
||||
supported=1;
|
||||
@@ -536,13 +536,13 @@ void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
}
|
||||
// Bits a1 and a0 determine the encoding. I'll add parsing as more samples become available
|
||||
if (!a1 && a0) // US TV parental guidelines
|
||||
{
|
||||
{
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
{
|
||||
xdsprint(sub, age);
|
||||
xdsprint(sub, content);
|
||||
}
|
||||
if (changed)
|
||||
if (changed)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n ",age);
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n ",content);
|
||||
@@ -552,18 +552,18 @@ void xds_do_content_advisory (struct cc_subtitle *sub, unsigned c1, unsigned c2)
|
||||
}
|
||||
if (!a0 || // MPA
|
||||
(a0 && a1 && !Da2 && !La3) // Canadian English Language Rating
|
||||
)
|
||||
)
|
||||
{
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
xdsprint(sub, rating);
|
||||
if (changed)
|
||||
if (changed)
|
||||
ccx_common_logging.log_ftn ("\rXDS: %s\n ",rating);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: %s\n",rating);
|
||||
}
|
||||
|
||||
if (changed && !supported)
|
||||
if (changed && !supported)
|
||||
ccx_common_logging.log_ftn ("XDS: Unsupported ContentAdvisory encoding, please submit sample.\n");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -614,7 +614,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
ccx_common_logging.log_ftn ("XDS program start time (DD/MM HH:MM) %02d-%02d %02d:%02d\n",date,month,hour,min);
|
||||
ccx_common_logging.gui_ftn(CCX_COMMON_LOGGING_GUI_XDS_PROGRAM_ID_NR, current_xds_min, current_xds_hour, current_xds_date, current_xds_month);
|
||||
xds_start_time_shown=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_LENGH_AND_CURRENT_TIME:
|
||||
@@ -624,7 +624,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
break;
|
||||
int min=cur_xds_payload[2] & 0x3f; // 6 bits
|
||||
int hour = cur_xds_payload[3] & 0x1f; // 5 bits
|
||||
if (!xds_program_length_shown)
|
||||
if (!xds_program_length_shown)
|
||||
ccx_common_logging.log_ftn ("\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
else
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS: Program length (HH:MM): %02d:%02d ",hour,min);
|
||||
@@ -646,7 +646,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
}
|
||||
if (cur_xds_payload_length>8) // Next two bytes (optional) available
|
||||
{
|
||||
int el_sec=cur_xds_payload[6] & 0x3f; // 6 bits
|
||||
int el_sec=cur_xds_payload[6] & 0x3f; // 6 bits
|
||||
if (!xds_program_length_shown)
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, ":%02d",el_sec);
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
@@ -670,7 +670,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS Program name: %s\n",xds_program_name);
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
xdsprint(sub, "Program name: %s",xds_program_name);
|
||||
if (cur_xds_packet_class==XDS_CLASS_CURRENT &&
|
||||
if (cur_xds_packet_class==XDS_CLASS_CURRENT &&
|
||||
strcmp (xds_program_name, current_xds_program_name)) // Change of program
|
||||
{
|
||||
//if (!ccx_options.gui_mode_reports)
|
||||
@@ -682,7 +682,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_PROGRAM_TYPE:
|
||||
was_proc=1;
|
||||
was_proc=1;
|
||||
if (cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
if (current_program_type_reported)
|
||||
@@ -709,9 +709,9 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
*str = '\0';
|
||||
tstr = str;
|
||||
for (int i=2;i<cur_xds_payload_length - 1; i++)
|
||||
{
|
||||
{
|
||||
if (cur_xds_payload[i]==0) // Padding
|
||||
continue;
|
||||
continue;
|
||||
if (!current_program_type_reported)
|
||||
ccx_common_logging.log_ftn ("[%02X-", cur_xds_payload[i]);
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
@@ -725,10 +725,10 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
if (!current_program_type_reported)
|
||||
{
|
||||
if (cur_xds_payload[i]>=0x20 && cur_xds_payload[i]<0x7F)
|
||||
ccx_common_logging.log_ftn ("%s",XDSProgramTypes[cur_xds_payload[i]-0x20]);
|
||||
ccx_common_logging.log_ftn ("%s",XDSProgramTypes[cur_xds_payload[i]-0x20]);
|
||||
else
|
||||
ccx_common_logging.log_ftn ("ILLEGAL VALUE");
|
||||
ccx_common_logging.log_ftn ("] ");
|
||||
ccx_common_logging.log_ftn ("] ");
|
||||
}
|
||||
}
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
@@ -736,18 +736,18 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
if (!current_program_type_reported)
|
||||
ccx_common_logging.log_ftn ("\n");
|
||||
current_program_type_reported=1;
|
||||
break;
|
||||
case XDS_TYPE_CONTENT_ADVISORY:
|
||||
was_proc=1;
|
||||
break;
|
||||
case XDS_TYPE_CONTENT_ADVISORY:
|
||||
was_proc=1;
|
||||
if (cur_xds_payload_length<5) // We need 2 data bytes
|
||||
break;
|
||||
xds_do_content_advisory (sub, cur_xds_payload[2],cur_xds_payload[3]);
|
||||
break;
|
||||
case XDS_TYPE_AUDIO_SERVICES:
|
||||
case XDS_TYPE_AUDIO_SERVICES:
|
||||
was_proc=1; // I don't have any sample with this.
|
||||
break;
|
||||
case XDS_TYPE_CGMS:
|
||||
was_proc=1;
|
||||
was_proc=1;
|
||||
xds_do_copy_generation_management_system (sub, cur_xds_payload[2],cur_xds_payload[3]);
|
||||
break;
|
||||
case XDS_TYPE_PROGRAM_DESC_1:
|
||||
@@ -766,9 +766,9 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
for (i=2;i<cur_xds_payload_length-1;i++)
|
||||
xds_desc[i-2]=cur_xds_payload[i];
|
||||
xds_desc[i-2]=0;
|
||||
|
||||
|
||||
if (xds_desc[0])
|
||||
{
|
||||
{
|
||||
int line_num=cur_xds_packet_type-XDS_TYPE_PROGRAM_DESC_1;
|
||||
if (strcmp (xds_desc, xds_program_description[line_num]))
|
||||
changed=1;
|
||||
@@ -778,7 +778,7 @@ int xds_do_current_and_future (struct cc_subtitle *sub)
|
||||
strcpy (xds_program_description[line_num], xds_desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "\rXDS description line %d: %s\n",line_num,xds_desc);
|
||||
}
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
@@ -819,13 +819,13 @@ int xds_do_channel (struct cc_subtitle *sub)
|
||||
was_proc=1;
|
||||
char xds_call_letters[7];
|
||||
if (cur_xds_payload_length != 7 && cur_xds_payload_length != 9) // We need 4-6 data bytes
|
||||
break;
|
||||
break;
|
||||
for (i=2;i<cur_xds_payload_length-1;i++)
|
||||
{
|
||||
if (cur_xds_payload)
|
||||
xds_call_letters[i-2]=cur_xds_payload[i];
|
||||
}
|
||||
xds_call_letters[i-2]=0;
|
||||
xds_call_letters[i-2]=0;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "XDS Network call letters: %s\n",xds_call_letters);
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
xdsprint (sub, "Call Letters: %s",xds_call_letters);
|
||||
@@ -838,11 +838,11 @@ int xds_do_channel (struct cc_subtitle *sub)
|
||||
}
|
||||
break;
|
||||
case XDS_TYPE_TSID:
|
||||
// According to CEA-608, data here (4 bytes) are used to identify the
|
||||
// According to CEA-608, data here (4 bytes) are used to identify the
|
||||
// "originating analog licensee". No interesting data for us.
|
||||
was_proc=1;
|
||||
if (cur_xds_payload_length<7) // We need 4 data bytes
|
||||
break;
|
||||
break;
|
||||
unsigned b1=(cur_xds_payload[2])&0x10; // Only low 4 bits from each byte
|
||||
unsigned b2=(cur_xds_payload[3])&0x10;
|
||||
unsigned b3=(cur_xds_payload[4])&0x10;
|
||||
@@ -874,7 +874,7 @@ int xds_do_misc ()
|
||||
{
|
||||
int was_proc=0;
|
||||
switch (cur_xds_packet_type)
|
||||
{
|
||||
{
|
||||
case XDS_TYPE_TIME_OF_DAY:
|
||||
{
|
||||
was_proc=1;
|
||||
@@ -884,11 +884,11 @@ int xds_do_misc ()
|
||||
int hour = cur_xds_payload[3] & 0x1f; // 5 bits
|
||||
int date = cur_xds_payload[4] & 0x1f; // 5 bits
|
||||
int month = cur_xds_payload[5] & 0xf; // 4 bits
|
||||
int reset_seconds = (cur_xds_payload[5] & 0x20);
|
||||
int reset_seconds = (cur_xds_payload[5] & 0x20);
|
||||
int day_of_week = cur_xds_payload[6] & 0x7;
|
||||
int year = (cur_xds_payload[7] & 0x3f) + 1990;
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Time of day: (YYYY/MM/DD) %04d/%02d/%02d (HH:SS) %02d:%02d DoW: %d Reset seconds: %d\n",
|
||||
year,month,date,hour,min, day_of_week, reset_seconds);
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Time of day: (YYYY/MM/DD) %04d/%02d/%02d (HH:SS) %02d:%02d DoW: %d Reset seconds: %d\n",
|
||||
year,month,date,hour,min, day_of_week, reset_seconds);
|
||||
break;
|
||||
}
|
||||
case XDS_TYPE_LOCAL_TIME_ZONE:
|
||||
@@ -900,13 +900,13 @@ int xds_do_misc ()
|
||||
int dst = (cur_xds_payload[2] & 0x20) >>5; // Daylight Saving Time
|
||||
int hour = cur_xds_payload[2] & 0x1f; // 5 bits
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Local Time Zone: %02d DST: %d\n",
|
||||
hour, dst);
|
||||
hour, dst);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
was_proc=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return was_proc;
|
||||
}
|
||||
|
||||
@@ -915,12 +915,12 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
|
||||
if (cur_xds_buffer_idx== -1 || /* Unknown buffer, or not in use (bug) */
|
||||
!xds_buffers[cur_xds_buffer_idx].in_use)
|
||||
return;
|
||||
cur_xds_packet_class=xds_buffers[cur_xds_buffer_idx].xds_class;
|
||||
cur_xds_packet_class=xds_buffers[cur_xds_buffer_idx].xds_class;
|
||||
cur_xds_payload=xds_buffers[cur_xds_buffer_idx].bytes;
|
||||
cur_xds_payload_length=xds_buffers[cur_xds_buffer_idx].used_bytes;
|
||||
cur_xds_packet_type=cur_xds_payload[1];
|
||||
cur_xds_payload[cur_xds_payload_length++]=0x0F; // The end byte itself, added to the packet
|
||||
|
||||
|
||||
int cs=0;
|
||||
for (int i=0; i<cur_xds_payload_length;i++)
|
||||
{
|
||||
@@ -935,15 +935,15 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "End of XDS. Class=%d (%s), size=%d Checksum OK: %d Used buffers: %d\n",
|
||||
cur_xds_packet_class,XDSclasses[cur_xds_packet_class],
|
||||
cur_xds_payload_length,
|
||||
cs==expected_checksum, how_many_used());
|
||||
cs==expected_checksum, how_many_used());
|
||||
|
||||
if (cs!=expected_checksum || cur_xds_payload_length<3)
|
||||
{
|
||||
ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Expected checksum: %02X Calculated: %02X\n", expected_checksum, cs);
|
||||
clear_xds_buffer (cur_xds_buffer_idx);
|
||||
clear_xds_buffer (cur_xds_buffer_idx);
|
||||
return; // Bad packets ignored as per specs
|
||||
}
|
||||
|
||||
|
||||
int was_proc=0; /* Indicated if the packet was processed. Not processed means "code to do it doesn't exist yet", not an error. */
|
||||
if (cur_xds_packet_type & 0x40) // Bit 6 set
|
||||
{
|
||||
@@ -956,21 +956,21 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
|
||||
if (!(ccx_common_logging.debug_mask & CCX_DMT_DECODER_XDS)) // Don't bother processing something we don't need
|
||||
{
|
||||
was_proc=1;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case XDS_CLASS_CURRENT: // Info on current program
|
||||
case XDS_CLASS_CURRENT: // Info on current program
|
||||
was_proc = xds_do_current_and_future(sub);
|
||||
break;
|
||||
case XDS_CLASS_CHANNEL:
|
||||
was_proc = xds_do_channel(sub);
|
||||
break;
|
||||
|
||||
|
||||
case XDS_CLASS_MISC:
|
||||
was_proc = xds_do_misc();
|
||||
break;
|
||||
case XDS_CLASS_PRIVATE: // CEA-608:
|
||||
// The Private Data Class is for use in any closed system for whatever that
|
||||
// system wishes. It shall not be defined by this standard now or in the future.
|
||||
// The Private Data Class is for use in any closed system for whatever that
|
||||
// system wishes. It shall not be defined by this standard now or in the future.
|
||||
if (ccx_decoders_xds_context.transcriptFormat.xds)
|
||||
was_proc=xds_do_private_data(sub);
|
||||
break;
|
||||
@@ -979,7 +979,7 @@ void do_end_of_xds (struct cc_subtitle *sub, unsigned char expected_checksum)
|
||||
was_proc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!was_proc)
|
||||
{
|
||||
ccx_common_logging.log_ftn ("Note: We found an currently unsupported XDS packet.\n");
|
||||
@@ -1,4 +1,3 @@
|
||||
//#include "ccextractor.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "spupng_encoder.h"
|
||||
@@ -7,6 +6,7 @@
|
||||
#include "ocr.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_decoders_xds.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
// These are the default settings for plain transcripts. No times, no CC or caption mode, and no XDS.
|
||||
ccx_encoders_transcript_format ccx_encoders_default_transcript_settings =
|
||||
@@ -17,7 +17,8 @@ ccx_encoders_transcript_format ccx_encoders_default_transcript_settings =
|
||||
.showCC = 0,
|
||||
.relativeTimestamp = 1,
|
||||
.xds = 0,
|
||||
.useColors = 1
|
||||
.useColors = 1,
|
||||
.isFinal = 0
|
||||
};
|
||||
|
||||
static const char *sami_header= // TODO: Revise the <!-- comments
|
||||
@@ -33,11 +34,18 @@ text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; colo
|
||||
</HEAD>\n\n\
|
||||
<BODY>\n";
|
||||
|
||||
static const char *smptett_header =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\
|
||||
<tt xmlns=\"http://www.w3.org/ns/ttml\" xml:lang=\"en\">\n\
|
||||
<body>\n<div>\n" ;
|
||||
|
||||
static const char *smptett_header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||
"<tt xmlns:ttm=\"http://www.w3.org/ns/ttml#metadata\" xmlns:tts=\"http://www.w3.org/ns/ttml#styling\" xmlns=\"http://www.w3.org/ns/ttml\" xml:lang=\"en\">\n"
|
||||
" <head>\n"
|
||||
" <styling>\n"
|
||||
" <style xml:id=\"speakerStyle\" tts:fontFamily=\"proportionalSansSerif\" tts:fontSize=\"150%\" tts:textAlign=\"center\" tts:displayAlign=\"center\" tts:color=\"white\" tts:textOutline=\"black 1px\"/>\n"
|
||||
" </styling>\n"
|
||||
" <layout>\n"
|
||||
" <region xml:id=\"speaker\" tts:origin=\"10% 80%\" tts:extent=\"80% 10%\" style=\"speakerStyle\"/>\n"
|
||||
" </layout>\n"
|
||||
" </head>\n"
|
||||
" <body>\n"
|
||||
" <div>\n";
|
||||
void write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
{
|
||||
int used;
|
||||
@@ -53,7 +61,7 @@ void write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
write(out->fh, ctx->buffer, used);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
sprintf ((char *) str,"</div></body></tt>\n");
|
||||
sprintf ((char *) str," </div>\n </body>\n</tt>\n");
|
||||
if (ccx_options.encoding!=CCX_ENC_UNICODE)
|
||||
{
|
||||
dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
|
||||
@@ -92,10 +100,10 @@ void write_subtitle_file_header(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
if (ccx_options.teletext_mode == CCX_TXT_IN_USE)
|
||||
rcwt_header[7] = 2; // sets file format version
|
||||
|
||||
write(out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
net_send_header(rcwt_header, sizeof(rcwt_header));
|
||||
else
|
||||
write(out->fh, rcwt_header, sizeof(rcwt_header));
|
||||
|
||||
break;
|
||||
case CCX_OF_SPUPNG:
|
||||
@@ -139,13 +147,13 @@ void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx
|
||||
if (ccx_options.transcript_settings.showStartTime){
|
||||
char buf1[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp){
|
||||
millis_to_date(start_time + subs_delay, buf1);
|
||||
millis_to_date(start_time + context->subs_delay, buf1);
|
||||
fdprintf(context->out->fh, "%s|", buf1);
|
||||
}
|
||||
else {
|
||||
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + subs_delay) % 1000;
|
||||
mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + context->subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + context->subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
|
||||
@@ -159,9 +167,9 @@ void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx
|
||||
fdprintf(context->out->fh, "%s|", buf2);
|
||||
}
|
||||
else {
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = end_time / 1000;
|
||||
int end_time_dec = end_time % 1000;
|
||||
mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = (end_time + context->subs_delay) / 1000;
|
||||
int end_time_dec = (end_time + context->subs_delay) % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
|
||||
@@ -224,119 +232,40 @@ int write_cc_buffer_as_transcript2(struct eia608_screen *data, struct encoder_ct
|
||||
}
|
||||
int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
uint8_t *pbuf;
|
||||
//char *filename;
|
||||
int ret = 0;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
//int used;
|
||||
|
||||
#ifdef ENABLE_OCR
|
||||
unsigned h1,m1,s1,ms1;
|
||||
unsigned h2,m2,s2,ms2;
|
||||
#endif
|
||||
LLONG start_time, end_time;
|
||||
//char timeline[128];
|
||||
int len = 0;
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
start_time = context->prev_start + subs_delay;
|
||||
start_time = context->prev_start + context->subs_delay;
|
||||
end_time = sub->start_time - 1;
|
||||
}
|
||||
else if ( !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
start_time = sub->start_time + subs_delay;
|
||||
start_time = sub->start_time + context->subs_delay;
|
||||
end_time = sub->end_time - 1;
|
||||
}
|
||||
|
||||
if(sub->nb_data == 0 )
|
||||
return 0;
|
||||
return ret;
|
||||
rect = sub->data;
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
if(x_pos == -1)
|
||||
{
|
||||
x_pos = rect[i].x;
|
||||
y_pos = rect[i].y;
|
||||
width = rect[i].w;
|
||||
height = rect[i].h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_pos > rect[i].x)
|
||||
{
|
||||
width += (x_pos - rect[i].x);
|
||||
x_pos = rect[i].x;
|
||||
}
|
||||
|
||||
if (rect[i].y < y_pos)
|
||||
{
|
||||
height += (y_pos - rect[i].y);
|
||||
y_pos = rect[i].y;
|
||||
}
|
||||
|
||||
if (rect[i].x + rect[i].w > x_pos + width)
|
||||
{
|
||||
width = rect[i].x + rect[i].w - x_pos;
|
||||
}
|
||||
|
||||
if (rect[i].y + rect[i].h > y_pos + height)
|
||||
{
|
||||
height = rect[i].y + rect[i].h - y_pos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( sub->flags & SUB_EOD_MARKER )
|
||||
context->prev_start = sub->start_time;
|
||||
pbuf = (uint8_t*) malloc(width * height);
|
||||
memset(pbuf, 0x0, width * height);
|
||||
|
||||
for(i = 0;i < sub->nb_data;i++)
|
||||
{
|
||||
x_off = rect[i].x - x_pos;
|
||||
y_off = rect[i].y - y_pos;
|
||||
for (y = 0; y < rect[i].h; y++)
|
||||
{
|
||||
for (x = 0; x < rect[i].w; x++)
|
||||
pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];
|
||||
|
||||
}
|
||||
}
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
#if ENABLE_OCR
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
|
||||
{
|
||||
char *token = NULL;
|
||||
token = strtok(str,"\r\n");
|
||||
token = strtok(rect[0].ocr_text ,"\r\n");
|
||||
while (token)
|
||||
{
|
||||
|
||||
@@ -345,14 +274,14 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
|
||||
char buf1[80];
|
||||
if (ccx_options.transcript_settings.relativeTimestamp)
|
||||
{
|
||||
millis_to_date(start_time + subs_delay, buf1);
|
||||
millis_to_date(start_time + context->subs_delay, buf1);
|
||||
fdprintf(context->out->fh, "%s|", buf1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mstotime(start_time + subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + subs_delay) % 1000;
|
||||
mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
|
||||
time_t start_time_int = (start_time + context->subs_delay) / 1000;
|
||||
int start_time_dec = (start_time + context->subs_delay) % 1000;
|
||||
struct tm *start_time_struct = gmtime(&start_time_int);
|
||||
strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
|
||||
fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
|
||||
@@ -369,7 +298,7 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
|
||||
}
|
||||
else
|
||||
{
|
||||
mstotime(get_fts() + subs_delay, &h2, &m2, &s2, &ms2);
|
||||
mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
|
||||
time_t end_time_int = end_time / 1000;
|
||||
int end_time_dec = end_time % 1000;
|
||||
struct tm *end_time_struct = gmtime(&end_time_int);
|
||||
@@ -394,11 +323,8 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
sub->nb_data = 0;
|
||||
freep(&sub->data);
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
@@ -407,7 +333,7 @@ void try_to_add_end_credits(struct encoder_ctx *context, struct ccx_s_write *out
|
||||
LLONG window, length, st, end;
|
||||
if (out->fh == -1)
|
||||
return;
|
||||
window=get_fts()-last_displayed_subs_ms-1;
|
||||
window=get_fts()-context->last_displayed_subs_ms-1;
|
||||
if (window<ccx_options.endcreditsforatleast.time_in_ms) // Won't happen, window is too short
|
||||
return;
|
||||
length=ccx_options.endcreditsforatmost.time_in_ms > window ?
|
||||
@@ -436,17 +362,17 @@ void try_to_add_end_credits(struct encoder_ctx *context, struct ccx_s_write *out
|
||||
void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
|
||||
{
|
||||
LLONG st, end, window, length;
|
||||
LLONG l = start_ms + subs_delay;
|
||||
LLONG l = start_ms + context->subs_delay;
|
||||
// We have a windows from last_displayed_subs_ms to l - we need to see if it fits
|
||||
|
||||
if (l<ccx_options.startcreditsnotbefore.time_in_ms) // Too early
|
||||
return;
|
||||
|
||||
if (last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
|
||||
if (context->last_displayed_subs_ms+1 > ccx_options.startcreditsnotafter.time_in_ms) // Too late
|
||||
return;
|
||||
|
||||
st = ccx_options.startcreditsnotbefore.time_in_ms>(last_displayed_subs_ms+1) ?
|
||||
ccx_options.startcreditsnotbefore.time_in_ms : (last_displayed_subs_ms+1); // When would credits actually start
|
||||
st = ccx_options.startcreditsnotbefore.time_in_ms>(context->last_displayed_subs_ms+1) ?
|
||||
ccx_options.startcreditsnotbefore.time_in_ms : (context->last_displayed_subs_ms+1); // When would credits actually start
|
||||
|
||||
end = ccx_options.startcreditsnotafter.time_in_ms<(l-1) ?
|
||||
ccx_options.startcreditsnotafter.time_in_ms : (l-1);
|
||||
@@ -460,7 +386,7 @@ void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
|
||||
window : ccx_options.startcreditsforatmost.time_in_ms;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Last subs: %lld Current position: %lld\n",
|
||||
last_displayed_subs_ms, l);
|
||||
context->last_displayed_subs_ms, l);
|
||||
dbg_print(CCX_DMT_VERBOSE, "Not before: %lld Not after: %lld\n",
|
||||
ccx_options.startcreditsnotbefore.time_in_ms,
|
||||
ccx_options.startcreditsnotafter.time_in_ms);
|
||||
@@ -488,7 +414,7 @@ void try_to_add_start_credits(struct encoder_ctx *context,LLONG start_ms)
|
||||
// Do nothing for the rest
|
||||
break;
|
||||
}
|
||||
startcredits_displayed=1;
|
||||
context->startcredits_displayed=1;
|
||||
return;
|
||||
|
||||
|
||||
@@ -508,7 +434,18 @@ int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void set_encoder_last_displayed_subs_ms(struct encoder_ctx *ctx, LLONG last_displayed_subs_ms)
|
||||
{
|
||||
ctx->last_displayed_subs_ms = last_displayed_subs_ms;
|
||||
}
|
||||
void set_encoder_subs_delay(struct encoder_ctx *ctx, LLONG subs_delay)
|
||||
{
|
||||
ctx->subs_delay = subs_delay;
|
||||
}
|
||||
void set_encoder_startcredits_displayed(struct encoder_ctx *ctx, int startcredits_displayed)
|
||||
{
|
||||
ctx->startcredits_displayed = startcredits_displayed;
|
||||
}
|
||||
void dinit_encoder(struct encoder_ctx *ctx)
|
||||
{
|
||||
|
||||
@@ -521,16 +458,19 @@ void dinit_encoder(struct encoder_ctx *ctx)
|
||||
|
||||
int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
{
|
||||
int wrote_something = 0 ;
|
||||
|
||||
if (ccx_options.extract!=1)
|
||||
context++;
|
||||
int wrote_something = 0;
|
||||
|
||||
if (sub->type == CC_608)
|
||||
{
|
||||
struct eia608_screen *data = NULL;
|
||||
for(data = sub->data; sub->nb_data ; sub->nb_data--,data++)
|
||||
{
|
||||
// Determine context based on channel. This replaces the code that was above, as this was incomplete (for cases where -12 was used for example)
|
||||
//if (ccx_options.extract!=1)
|
||||
//context++;
|
||||
if (data->my_field == 2)
|
||||
context++;
|
||||
|
||||
new_sentence=1;
|
||||
|
||||
if(data->format == SFORMAT_XDS)
|
||||
@@ -548,17 +488,17 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_srt(data, context);
|
||||
break;
|
||||
case CCX_OF_SAMI:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_sami(data, context);
|
||||
break;
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, data->start_time);
|
||||
wrote_something = write_cc_buffer_as_smptett(data, context);
|
||||
break;
|
||||
@@ -572,7 +512,7 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
break;
|
||||
}
|
||||
if (wrote_something)
|
||||
last_displayed_subs_ms=get_fts()+subs_delay;
|
||||
context->last_displayed_subs_ms=get_fts() + context->subs_delay;
|
||||
|
||||
if (ccx_options.gui_mode_reports)
|
||||
write_cc_buffer_to_gui(sub->data, context);
|
||||
@@ -584,15 +524,15 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub)
|
||||
switch (ccx_options.write_format)
|
||||
{
|
||||
case CCX_OF_SRT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_srt(sub, context);
|
||||
case CCX_OF_SAMI:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_sami(sub, context);
|
||||
case CCX_OF_SMPTETT:
|
||||
if (!startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
if (!context->startcredits_displayed && ccx_options.start_credits_text!=NULL)
|
||||
try_to_add_start_credits(context, sub->start_time);
|
||||
wrote_something = write_cc_bitmap_as_smptett(sub, context);
|
||||
case CCX_OF_TRANSCRIPT:
|
||||
@@ -628,7 +568,7 @@ void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *cont
|
||||
|
||||
ms_start = data->start_time;
|
||||
|
||||
ms_start += subs_delay;
|
||||
ms_start += context->subs_delay;
|
||||
if (ms_start<0) // Drop screens that because of subs_delay start too early
|
||||
return;
|
||||
int time_reported = 0;
|
||||
@@ -14,8 +14,8 @@ if (ctx->buffer == NULL) { fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bai
|
||||
extern ccx_encoders_transcript_format ccx_encoders_default_transcript_settings;
|
||||
|
||||
/**
|
||||
* Context of encoder, This structure gives single interface
|
||||
* to all encoder
|
||||
* Context of encoder, This structure gives single interface
|
||||
* to all encoder
|
||||
*/
|
||||
struct encoder_ctx
|
||||
{
|
||||
@@ -29,6 +29,10 @@ struct encoder_ctx
|
||||
struct ccx_s_write *out;
|
||||
/* start time of previous sub */
|
||||
LLONG prev_start;
|
||||
|
||||
LLONG subs_delay;
|
||||
LLONG last_displayed_subs_ms;
|
||||
int startcredits_displayed;
|
||||
};
|
||||
|
||||
#define INITIAL_ENC_BUFFER_CAPACITY 2048
|
||||
@@ -40,24 +44,24 @@ struct encoder_ctx
|
||||
*
|
||||
* @param ctx preallocated encoder ctx
|
||||
* @param out output context
|
||||
*
|
||||
*
|
||||
* @return 0 on SUCESS, -1 on failure
|
||||
*/
|
||||
int init_encoder(struct encoder_ctx *ctx,struct ccx_s_write *out);
|
||||
|
||||
/**
|
||||
* try to add end credits in subtitle file and then write subtitle
|
||||
* try to add end credits in subtitle file and then write subtitle
|
||||
* footer
|
||||
*
|
||||
* deallocate encoder ctx, so before using encoder_ctx again
|
||||
* deallocate encoder ctx, so before using encoder_ctx again
|
||||
* after deallocating user need to allocate encoder ctx again
|
||||
*
|
||||
*
|
||||
* @oaram ctx Initialized encoder ctx using init_encoder
|
||||
*/
|
||||
void dinit_encoder(struct encoder_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @param ctx encoder context
|
||||
* @param ctx encoder context
|
||||
* @param sub subtitle context returned by decoder
|
||||
*/
|
||||
int encode_sub(struct encoder_ctx *ctx,struct cc_subtitle *sub);
|
||||
@@ -78,4 +82,7 @@ int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context
|
||||
int write_cc_bitmap_as_smptett(struct cc_subtitle *sub, struct encoder_ctx *context);
|
||||
|
||||
|
||||
void set_encoder_last_displayed_subs_ms(struct encoder_ctx *ctx, LLONG last_displayed_subs_ms);
|
||||
void set_encoder_subs_delay(struct encoder_ctx *ctx, LLONG subs_delay);
|
||||
void set_encoder_startcredits_displayed(struct encoder_ctx *ctx, int startcredits_displayed);
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@ char **spell_lower = NULL;
|
||||
char **spell_correct = NULL;
|
||||
int spell_words = 0;
|
||||
int spell_capacity = 0;
|
||||
|
||||
struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
|
||||
// Some basic English words, so user-defined doesn't have to
|
||||
// include the common stuff
|
||||
static const char *spell_builtin[] =
|
||||
@@ -97,7 +97,7 @@ void capitalize(int line_num, struct eia608_screen *data)
|
||||
|
||||
// Encodes a generic string. Note that since we use the encoders for closed caption
|
||||
// data, text would have to be encoded as CCs... so using special characters here
|
||||
// it's a bad idea.
|
||||
// it's a bad idea.
|
||||
unsigned encode_line(unsigned char *buffer, unsigned char *text)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
@@ -194,7 +194,7 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
|
||||
buffer += encode_line(buffer, (unsigned char*)color_text[its_col][1]);
|
||||
if (its_col == COL_USERDEFINED)
|
||||
{
|
||||
// The previous sentence doesn't copy the whole
|
||||
// The previous sentence doesn't copy the whole
|
||||
// <font> tag, just up to the quote before the color
|
||||
buffer += encode_line(buffer, (unsigned char*)usercolor_rgb);
|
||||
buffer += encode_line(buffer, (unsigned char*) "\">");
|
||||
@@ -334,7 +334,7 @@ int add_word(const char *word)
|
||||
}
|
||||
|
||||
|
||||
int add_built_in_words()
|
||||
int add_built_in_words(void)
|
||||
{
|
||||
if (!spell_builtin_added)
|
||||
{
|
||||
@@ -356,7 +356,7 @@ int add_built_in_words()
|
||||
* @param size size of each element
|
||||
* @param compar Comparison function, which is called with three argument
|
||||
* that point to the objects being compared and arg.
|
||||
* @param arg argument passed as it is to compare function
|
||||
* @param arg argument passed as it is, to compare function
|
||||
*/
|
||||
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg)
|
||||
{
|
||||
@@ -378,7 +378,8 @@ void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, con
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
void ccx_encoders_helpers_perform_shellsort_words(){
|
||||
void ccx_encoders_helpers_perform_shellsort_words(void)
|
||||
{
|
||||
shell_sort(spell_lower, spell_words, sizeof(*spell_lower), string_cmp2, NULL);
|
||||
shell_sort(spell_correct, spell_words, sizeof(*spell_correct), string_cmp2, NULL);
|
||||
}
|
||||
@@ -18,7 +18,8 @@ struct ccx_encoders_helpers_settings_t {
|
||||
int no_font_color;
|
||||
int no_type_setting;
|
||||
enum ccx_encoding_type encoding;
|
||||
} ccx_encoders_helpers_settings;
|
||||
};
|
||||
extern struct ccx_encoders_helpers_settings_t ccx_encoders_helpers_settings;
|
||||
|
||||
// Helper functions
|
||||
void correct_case(int line_num, struct eia608_screen *data);
|
||||
@@ -28,11 +29,11 @@ unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct ei
|
||||
|
||||
int string_cmp(const void *p1, const void *p2);
|
||||
int string_cmp2(const void *p1, const void *p2, void *arg);
|
||||
int add_built_in_words();
|
||||
int add_built_in_words(void);
|
||||
int add_word(const char *word);
|
||||
|
||||
void shell_sort(void *base, int nb, size_t size, int(*compar)(const void*p1, const void *p2, void*arg), void *arg);
|
||||
|
||||
void ccx_encoders_helpers_perform_shellsort_words();
|
||||
void ccx_encoders_helpers_perform_shellsort_words(void);
|
||||
void ccx_encoders_helpers_setup(enum ccx_encoding_type encoding, int no_font_color, int no_type_setting, int trim_subs);
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef CCX_ENCODERS_STRUCTS_H
|
||||
|
||||
typedef struct {
|
||||
typedef struct ccx_encoders_transcript_format {
|
||||
// TODO: add more options, and (perhaps) reduce other ccextractor options?
|
||||
int showStartTime, showEndTime; // Show start and/or end time.
|
||||
int showMode; // Show which mode if available (E.G.: POP, RU1, ...)
|
||||
int showCC; // Show which CC channel has been captured.
|
||||
int showMode; // Show which mode if available (E.G.: POP, RU1, ...)
|
||||
int showCC; // Show which CC channel has been captured.
|
||||
int relativeTimestamp; // Timestamps relative to start of sample or in UTC?
|
||||
int xds; // Show XDS or not
|
||||
int useColors; // Add colors or no colors
|
||||
int isFinal; // Used to determine if these parameters should be changed afterwards.
|
||||
|
||||
} ccx_encoders_transcript_format;
|
||||
|
||||
@@ -21,4 +22,4 @@ struct ccx_s_write
|
||||
};
|
||||
|
||||
#define CCX_ENCODERS_STRUCTS_H
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "configuration.h"
|
||||
#include <stddef.h>
|
||||
#define CNF_FILE "ccextractor.cnf"
|
||||
@@ -43,7 +44,7 @@ static int set_int(void *var, char*val)
|
||||
|
||||
struct conf_map configuration_map[] = {
|
||||
{"INPUT_SOURCE",offsetof(struct ccx_s_options,input_source),set_int},
|
||||
{"BUFFER_INPUT",offsetof(struct ccx_s_options,buffer_input),set_int},
|
||||
{"BUFFER_INPUT",offsetof(struct ccx_s_options,buffer_input),set_int},
|
||||
{"NOFONT_COLOR",offsetof(struct ccx_s_options,nofontcolor),set_int},
|
||||
{"NOTYPE_SETTING",offsetof(struct ccx_s_options,notypesetting),set_int},
|
||||
{"CODEC",offsetof(struct ccx_s_options,codec),set_int},
|
||||
@@ -59,7 +60,7 @@ struct conf_map configuration_map[] = {
|
||||
{"END_CREDITS_FOR_ATMOST",offsetof(struct ccx_s_options,endcreditsforatmost),set_time},
|
||||
{"VIDEO_EDITED",offsetof(struct ccx_s_options,binary_concat),set_int},
|
||||
{"GOP_TIME",offsetof(struct ccx_s_options,use_gop_as_pts),set_int},
|
||||
{"FIX_PADDINDG",offsetof(struct ccx_s_options,fix_padding),set_int},
|
||||
{"FIX_PADDINDG",offsetof(struct ccx_s_options,fix_padding),set_int},
|
||||
{"TRIM",offsetof(struct ccx_s_options,trim_subs),set_int},
|
||||
{"GUI_MODE_REPORTS",offsetof(struct ccx_s_options,gui_mode_reports),set_int},
|
||||
{"NO_PROGRESS_BAR",offsetof(struct ccx_s_options,no_progress_bar),set_int},
|
||||
@@ -67,7 +68,7 @@ struct conf_map configuration_map[] = {
|
||||
{"CAP_FILE",offsetof(struct ccx_s_options,sentence_cap_file),set_string},
|
||||
{"PROGRAM_NUMBER",offsetof(struct ccx_s_options,ts_forced_program),set_int},
|
||||
{"AUTO_PROGRAM",offsetof(struct ccx_s_options,ts_autoprogram),set_int},
|
||||
{"STREAM",offsetof(struct ccx_s_options,live_stream),set_int},
|
||||
{"STREAM",offsetof(struct ccx_s_options,live_stream),set_int},
|
||||
{"START_AT",offsetof(struct ccx_s_options,extraction_start),set_time},
|
||||
{"END_AT",offsetof(struct ccx_s_options,extraction_end),set_time},
|
||||
{"INVASTIGATE_PACKET",offsetof(struct ccx_s_options,investigate_packets),set_int},
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "dvb_subtitle_decoder.h"
|
||||
#include "utility.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
#include "ocr.h"
|
||||
|
||||
#define DVBSUB_PAGE_SEGMENT 0x10
|
||||
#define DVBSUB_REGION_SEGMENT 0x11
|
||||
@@ -272,6 +273,9 @@ typedef struct DVBSubContext
|
||||
int lang_index;
|
||||
int version;
|
||||
int time_out;
|
||||
#ifdef ENABLE_OCR
|
||||
void *ocr_ctx;
|
||||
#endif
|
||||
DVBSubRegion *region_list;
|
||||
DVBSubCLUT *clut_list;
|
||||
DVBSubObject *object_list;
|
||||
@@ -429,6 +433,14 @@ void* dvbsub_init_decoder(struct dvb_config* cfg)
|
||||
ctx->ancillary_id = cfg->ancillary_id[0];
|
||||
ctx->lang_index = cfg->lang_index[0];
|
||||
|
||||
#ifdef ENABLE_OCR
|
||||
ctx->ocr_ctx = init_ocr(ctx->lang_index);
|
||||
if(!ctx->ocr_ctx)
|
||||
{
|
||||
freep(&ctx);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
ctx->version = -1;
|
||||
|
||||
default_clut.id = -1;
|
||||
@@ -1425,6 +1437,7 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
struct cc_bitmap *rect = NULL;
|
||||
uint32_t *clut_table;
|
||||
int offset_x=0, offset_y=0;
|
||||
int ret = 0;
|
||||
|
||||
sub->type = CC_BITMAP;
|
||||
sub->lang_index = ctx->lang_index;
|
||||
@@ -1440,22 +1453,27 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
if (region && region->dirty)
|
||||
sub->nb_data++;
|
||||
}
|
||||
sub->start_time = get_visible_start();
|
||||
sub->end_time = sub->start_time + ( ctx->time_out * 1000 );
|
||||
sub->flags |= SUB_EOD_MARKER;
|
||||
sub->got_output = 1;
|
||||
if( sub->nb_data <= 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rect = malloc( sizeof(struct cc_bitmap) * sub->nb_data);
|
||||
if(!rect)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sub->start_time = get_visible_start();
|
||||
sub->end_time = sub->start_time + ( ctx->time_out * 1000 );
|
||||
sub->flags |= SUB_EOD_MARKER;
|
||||
sub->got_output = 1;
|
||||
sub->data = rect;
|
||||
for (display = ctx->display_list; display; display = display->next)
|
||||
{
|
||||
#ifdef ENABLE_OCR
|
||||
char *ocr_str = NULL;
|
||||
#endif
|
||||
region = get_region(ctx, display->region_id);
|
||||
|
||||
if (!region)
|
||||
@@ -1495,6 +1513,11 @@ static int write_dvb_sub(void *dvb_ctx, struct cc_subtitle *sub)
|
||||
|
||||
rect->data[0] = malloc(region->buf_size);
|
||||
memcpy(rect->data[0], region->pbuf, region->buf_size);
|
||||
#ifdef ENABLE_OCR
|
||||
ret = ocr_rect(ctx->ocr_ctx, rect, &ocr_str);
|
||||
if(ret >= 0)
|
||||
rect->ocr_text = ocr_str;
|
||||
#endif
|
||||
rect++;
|
||||
|
||||
}
|
||||
@@ -1523,12 +1546,12 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
|
||||
int segment_type;
|
||||
int page_id;
|
||||
int segment_length;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int got_segment = 0;
|
||||
|
||||
if (buf_size <= 6 || *buf != 0x0f)
|
||||
{
|
||||
mprint("incomplete or broken packet");
|
||||
mprint("incomplete or broken packet\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1547,7 +1570,7 @@ int dvbsub_decode(void *dvb_ctx, const unsigned char *buf, int buf_size, struct
|
||||
|
||||
if (p_end - p < segment_length)
|
||||
{
|
||||
mprint("incomplete or broken packet");
|
||||
mprint("incomplete or broken packet\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#define MAX_LANGUAGE_PER_DESC 5
|
||||
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
@@ -76,8 +76,8 @@ int parse_dvb_description(struct dvb_config* cfg, unsigned char*data,
|
||||
*
|
||||
* @param dvb_ctx context of dvb which was returned by dvbsub_init_decoder
|
||||
*
|
||||
* @param out output context returned by init_write
|
||||
*
|
||||
* @param out output context returned by init_write
|
||||
*
|
||||
*/
|
||||
void dvbsub_set_write(void *dvb_ctx, struct ccx_s_write *out);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
// Functions to parse a mpeg-2 data stream, see ISO/IEC 13818-2 6.2
|
||||
|
||||
static int no_bitstream_error = 0;
|
||||
@@ -19,24 +20,24 @@ static unsigned pulldownfields = 0;
|
||||
|
||||
static uint8_t search_start_code(struct bitstream *esstream);
|
||||
static uint8_t next_start_code(struct bitstream *esstream);
|
||||
static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_seq_info(struct bitstream *esstream);
|
||||
static int sequence_header(struct bitstream *esstream);
|
||||
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream);
|
||||
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream);
|
||||
static int sequence_ext(struct bitstream *esstream);
|
||||
static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int pic_header(struct bitstream *esstream);
|
||||
static int pic_coding_ext(struct bitstream *esstream);
|
||||
static int read_eau_info(struct bitstream *esstream, int udtype , struct cc_subtitle *sub);
|
||||
static int extension_and_user_data(struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int read_pic_data(struct bitstream *esstream);
|
||||
|
||||
|
||||
/* Process a mpeg-2 data stream with "lenght" bytes in buffer "data".
|
||||
* The number of processed bytes is returned.
|
||||
* Defined in ISO/IEC 13818-2 6.2 */
|
||||
LLONG process_m2v (unsigned char *data, LLONG length,struct cc_subtitle *sub)
|
||||
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG length,struct cc_subtitle *sub)
|
||||
{
|
||||
if (length<8) // Need to look ahead 8 bytes
|
||||
return length;
|
||||
@@ -47,7 +48,7 @@ LLONG process_m2v (unsigned char *data, LLONG length,struct cc_subtitle *sub)
|
||||
|
||||
// Process data. The return value is ignored as esstream.pos holds
|
||||
// the information how far the parsing progressed.
|
||||
es_video_sequence(&esstream, sub);
|
||||
es_video_sequence(ctx, &esstream, sub);
|
||||
|
||||
// This returns how many bytes were processed and can therefore
|
||||
// be discarded from "buffer". "esstream.pos" points to the next byte
|
||||
@@ -184,7 +185,7 @@ static uint8_t next_start_code(struct bitstream *esstream)
|
||||
// Otherwise. estream->pos shall point to the position where
|
||||
// the next call will continue, i.e. the possible begin of an
|
||||
// unfinished video sequence or after the finished sequence.
|
||||
static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int es_video_sequence(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
// Avoid "Skip forward" message on first call and later only
|
||||
// once per search.
|
||||
@@ -259,7 +260,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
|
||||
|
||||
if (!in_pic_data && startcode == 0xB3)
|
||||
{
|
||||
if (!read_seq_info(esstream))
|
||||
if (!read_seq_info(ctx, esstream))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -271,7 +272,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
|
||||
|
||||
if (!in_pic_data && startcode == 0xB8)
|
||||
{
|
||||
if (!read_gop_info(esstream,sub))
|
||||
if (!read_gop_info(ctx, esstream,sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -283,7 +284,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
|
||||
|
||||
if (!in_pic_data && startcode == 0x00)
|
||||
{
|
||||
if (!read_pic_info(esstream, sub))
|
||||
if (!read_pic_info(ctx, esstream, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -299,7 +300,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
|
||||
// This check needs to be before the "in_pic_data" part.
|
||||
if ( saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
|
||||
{
|
||||
if (!read_eau_info(esstream, saw_seqgoppic-1, sub))
|
||||
if (!read_eau_info(ctx, esstream, saw_seqgoppic-1, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
no_bitstream_error = 0;
|
||||
@@ -344,7 +345,7 @@ static int es_video_sequence(struct bitstream *esstream, struct cc_subtitle *sub
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_seq_info(struct bitstream *esstream)
|
||||
static int read_seq_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Sequence Info\n");
|
||||
|
||||
@@ -357,7 +358,7 @@ static int read_seq_info(struct bitstream *esstream)
|
||||
// after getting more.
|
||||
unsigned char *video_seq_start = esstream->pos;
|
||||
|
||||
sequence_header(esstream);
|
||||
sequence_header(ctx, esstream);
|
||||
sequence_ext(esstream);
|
||||
// FIXME: if sequence extension is missing this is not MPEG-2,
|
||||
// or broken. Set bitstream error.
|
||||
@@ -381,7 +382,7 @@ static int read_seq_info(struct bitstream *esstream)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int sequence_header(struct bitstream *esstream)
|
||||
static int sequence_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Sequence header\n");
|
||||
|
||||
@@ -397,10 +398,10 @@ static int sequence_header(struct bitstream *esstream)
|
||||
unsigned aspect_ratio = (unsigned) read_bits(esstream,4);
|
||||
unsigned frame_rate = (unsigned) read_bits(esstream,4);
|
||||
|
||||
file_report.width = hor_size;
|
||||
file_report.height = vert_size;
|
||||
file_report.aspect_ratio = aspect_ratio;
|
||||
file_report.frame_rate = frame_rate;
|
||||
ctx->freport.width = hor_size;
|
||||
ctx->freport.height = vert_size;
|
||||
ctx->freport.aspect_ratio = aspect_ratio;
|
||||
ctx->freport.frame_rate = frame_rate;
|
||||
|
||||
// Discard some information
|
||||
read_bits(esstream, 18+1+10+1);
|
||||
@@ -424,7 +425,7 @@ static int sequence_header(struct bitstream *esstream)
|
||||
// If horizontal/vertical size, framerate and/or aspect
|
||||
// ratio are ilegal, we discard the
|
||||
// whole sequence info.
|
||||
if (vert_size >= 288 && vert_size <= 1088 &&
|
||||
if (vert_size >= 288 && vert_size <= 1088 &&
|
||||
hor_size >= 352 && hor_size <= 1920 &&
|
||||
hor_size / vert_size >= 352/576 && hor_size / vert_size <= 2 &&
|
||||
frame_rate>0 && frame_rate<9 &&
|
||||
@@ -437,7 +438,7 @@ static int sequence_header(struct bitstream *esstream)
|
||||
/ MPEG_CLOCK_FREQ);
|
||||
mprint (" at %02u:%02u",cur_sec/60, cur_sec % 60);
|
||||
}
|
||||
mprint ("\n");
|
||||
mprint ("\n");
|
||||
mprint ("[%u * %u] [AR: %s] [FR: %s]",
|
||||
hor_size,vert_size,
|
||||
aspect_ratio_types[aspect_ratio],
|
||||
@@ -454,8 +455,8 @@ static int sequence_header(struct bitstream *esstream)
|
||||
activity_video_info (hor_size,vert_size,
|
||||
aspect_ratio_types[aspect_ratio],
|
||||
framerates_types[frame_rate]);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nInvalid sequence header:\n");
|
||||
dbg_print(CCX_DMT_VERBOSE, "V: %u H: %u FR: %u AS: %u\n",
|
||||
@@ -526,7 +527,7 @@ static int sequence_ext(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int read_gop_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read GOP Info\n");
|
||||
|
||||
@@ -539,7 +540,7 @@ static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// after getting more.
|
||||
unsigned char *gop_info_start = esstream->pos;
|
||||
|
||||
gop_header(esstream, sub);
|
||||
gop_header(ctx, esstream, sub);
|
||||
//extension_and_user_data(esstream);
|
||||
|
||||
if (esstream->error)
|
||||
@@ -560,7 +561,7 @@ static int read_gop_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int gop_header(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "GOP header\n");
|
||||
|
||||
@@ -593,7 +594,7 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(sub);
|
||||
process_hdcc(ctx, sub);
|
||||
}
|
||||
|
||||
// Last GOPs pulldown frames
|
||||
@@ -611,19 +612,19 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// are 20% or more deviation.
|
||||
if ( (ccx_options.debug_mask & CCX_DMT_TIME)
|
||||
&& ((gtc.ms - gop_time.ms // more than 20% longer
|
||||
> frames_since_last_gop*1000.0/current_fps*1.2)
|
||||
> ctx->frames_since_last_gop*1000.0/current_fps*1.2)
|
||||
||
|
||||
(gtc.ms - gop_time.ms // or 20% shorter
|
||||
< frames_since_last_gop*1000.0/current_fps*0.8))
|
||||
< ctx->frames_since_last_gop*1000.0/current_fps*0.8))
|
||||
&& first_gop_time.inited )
|
||||
{
|
||||
mprint("\rWarning: Jump in GOP timing.\n");
|
||||
mprint(" (old) %s",
|
||||
print_mstime(gop_time.ms));
|
||||
mprint(" + %s (%uF)",
|
||||
print_mstime((LLONG) (frames_since_last_gop
|
||||
print_mstime((LLONG) (ctx->frames_since_last_gop
|
||||
*1000.0/current_fps)),
|
||||
frames_since_last_gop);
|
||||
ctx->frames_since_last_gop);
|
||||
mprint(" != (new) %s\n",
|
||||
print_mstime(gtc.ms));
|
||||
}
|
||||
@@ -656,9 +657,9 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
|
||||
gop_time = gtc;
|
||||
|
||||
frames_since_last_gop=0;
|
||||
ctx->frames_since_last_gop=0;
|
||||
// Indicate that we read a gop header (since last frame number 0)
|
||||
saw_gop_header = 1;
|
||||
ctx->saw_gop_header = 1;
|
||||
|
||||
// If we use GOP timing, reconstruct the PTS from the GOP
|
||||
if (ccx_options.use_gop_as_pts==1)
|
||||
@@ -697,7 +698,7 @@ static int gop_header(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
static int read_pic_info(struct lib_ccx_ctx *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info\n");
|
||||
|
||||
@@ -728,18 +729,18 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// A new anchor frame - flush buffered caption data. Might be flushed
|
||||
// in GOP header already.
|
||||
if (picture_coding_type==CCX_FRAME_TYPE_I_FRAME || picture_coding_type==CCX_FRAME_TYPE_P_FRAME)
|
||||
{
|
||||
// if (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
|
||||
// (temporal_reference != current_tref))
|
||||
// {
|
||||
{
|
||||
if (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
|
||||
(temporal_reference != current_tref))
|
||||
{
|
||||
// NOTE: process_hdcc() needs to be called before set_fts() as it
|
||||
// uses fts_now to re-create the timeline !!!!!
|
||||
if (has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(sub);
|
||||
process_hdcc(ctx, sub);
|
||||
}
|
||||
anchor_hdcc(temporal_reference);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
current_tref = temporal_reference;
|
||||
@@ -757,7 +758,7 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
(unsigned) (current_pts), temporal_reference,
|
||||
pict_types[picture_coding_type],
|
||||
(unsigned) (frames_since_ref_time),
|
||||
(unsigned) (frames_since_last_gop));
|
||||
(unsigned) (ctx->frames_since_last_gop));
|
||||
dbg_print(CCX_DMT_VIDES, " t:%d r:%d p:%d", top_field_first,
|
||||
repeat_first_field, progressive_frame);
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
@@ -771,16 +772,16 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
// the beginning of the GOP, otherwise it is now.
|
||||
if(temporal_reference == 0)
|
||||
{
|
||||
last_gop_length = maxtref + 1;
|
||||
ctx->last_gop_length = maxtref + 1;
|
||||
maxtref = temporal_reference;
|
||||
|
||||
// frames_since_ref_time is used in set_fts()
|
||||
|
||||
if( saw_gop_header )
|
||||
if( ctx->saw_gop_header )
|
||||
{
|
||||
// This time (fts_at_gop_start) that was set in the
|
||||
// GOP header and it might be off by one GOP. See the comment there.
|
||||
frames_since_ref_time = frames_since_last_gop; // Should this be 0?
|
||||
frames_since_ref_time = ctx->frames_since_last_gop; // Should this be 0?
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -795,39 +796,39 @@ static int read_pic_info(struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
print_debug_timing();
|
||||
}
|
||||
|
||||
saw_gop_header = 0; // Reset the value
|
||||
ctx->saw_gop_header = 0; // Reset the value
|
||||
}
|
||||
|
||||
if ( !saw_gop_header && picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
|
||||
if ( !ctx->saw_gop_header && picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
|
||||
{
|
||||
// A new GOP beginns with an I-frame. Lets hope there are
|
||||
// never more than one per GOP
|
||||
frames_since_last_gop = 0;
|
||||
ctx->frames_since_last_gop = 0;
|
||||
}
|
||||
|
||||
// Set maxtref
|
||||
if( temporal_reference > maxtref ) {
|
||||
maxtref = temporal_reference;
|
||||
if (maxtref+1 > max_gop_length)
|
||||
max_gop_length = maxtref+1;
|
||||
if (maxtref+1 > ctx->max_gop_length)
|
||||
ctx->max_gop_length = maxtref+1;
|
||||
}
|
||||
|
||||
unsigned extraframe = 0;
|
||||
if (repeat_first_field)
|
||||
{
|
||||
pulldownfields++;
|
||||
total_pulldownfields++;
|
||||
if ( current_progressive_sequence || !(total_pulldownfields%2) )
|
||||
ctx->total_pulldownfields++;
|
||||
if ( current_progressive_sequence || !(ctx->total_pulldownfields%2) )
|
||||
extraframe = 1;
|
||||
if ( current_progressive_sequence && top_field_first )
|
||||
extraframe = 2;
|
||||
dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
|
||||
total_pulldownfields, extraframe);
|
||||
ctx->total_pulldownfields, extraframe);
|
||||
}
|
||||
|
||||
total_pulldownframes += extraframe;
|
||||
ctx->total_pulldownframes += extraframe;
|
||||
total_frames_count += 1+extraframe;
|
||||
frames_since_last_gop += 1+extraframe;
|
||||
ctx->frames_since_last_gop += 1+extraframe;
|
||||
frames_since_ref_time += 1+extraframe;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read PIC Info - processed\n\n");
|
||||
@@ -944,7 +945,7 @@ static int pic_coding_ext(struct bitstream *esstream)
|
||||
// If a bitstream syntax problem occured the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
// will point to where we want to restart after getting more.
|
||||
static int read_eau_info(struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
static int read_eau_info(struct lib_ccx_ctx* ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Read Extension and User Info\n");
|
||||
|
||||
@@ -958,7 +959,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype, struct cc_subti
|
||||
// user data is not evaluated twice. Should the function run out of
|
||||
// data it will make sure that esstream points to where we want to
|
||||
// continue after getting more.
|
||||
if( !extension_and_user_data(esstream, udtype, sub) )
|
||||
if( !extension_and_user_data(ctx, esstream, udtype, sub) )
|
||||
{
|
||||
if (esstream->error)
|
||||
dbg_print(CCX_DMT_VERBOSE, "\nWarning: Retry while reading Extension and User Data!\n");
|
||||
@@ -977,7 +978,7 @@ static int read_eau_info(struct bitstream *esstream, int udtype, struct cc_subti
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int extension_and_user_data(struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
static int extension_and_user_data(struct lib_ccx_ctx *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Extension and user data(%d)\n", udtype);
|
||||
|
||||
@@ -1001,7 +1002,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype, struc
|
||||
// Advanve esstream to the next startcode. Verify that
|
||||
// the whole extension was available and discard blocks
|
||||
// followed by PACK headers. The latter usually indicates
|
||||
// a PS treated as an ES.
|
||||
// a PS treated as an ES.
|
||||
uint8_t nextstartcode = search_start_code(esstream);
|
||||
if (nextstartcode == 0xBA)
|
||||
{
|
||||
@@ -1029,7 +1030,7 @@ static int extension_and_user_data(struct bitstream *esstream, int udtype, struc
|
||||
{
|
||||
struct bitstream ustream;
|
||||
init_bitstream(&ustream, dstart, esstream->pos);
|
||||
user_data(&ustream, udtype, sub);
|
||||
user_data(ctx, &ustream, udtype, sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
|
||||
|
||||
// Parse the user data for captions. The udtype variable denotes
|
||||
@@ -9,8 +9,10 @@
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if ustream->error
|
||||
// is FALSE, parsing can set ustream->error to TRUE.
|
||||
int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype);
|
||||
|
||||
// Shall not happen
|
||||
@@ -23,14 +25,14 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
}
|
||||
|
||||
// Do something
|
||||
stat_numuserheaders++;
|
||||
ctx->stat_numuserheaders++;
|
||||
//header+=4;
|
||||
|
||||
unsigned char *ud_header = next_bytes(ustream, 4);
|
||||
if (ustream->error || ustream->bitsleft <= 0)
|
||||
{
|
||||
{
|
||||
return 0; // Actually discarded on call.
|
||||
// CFS: Seen in Stick_VHS.mpg.
|
||||
// CFS: Seen in Stick_VHS.mpg.
|
||||
// fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!");
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
// <http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/SCC_FORMAT.HTML>
|
||||
if ( !memcmp(ud_header,"\x43\x43", 2 ) )
|
||||
{
|
||||
stat_dvdccheaders++;
|
||||
ctx->stat_dvdccheaders++;
|
||||
|
||||
// Probably unneeded, but keep looking for extra caption blocks
|
||||
int maybeextracb = 1;
|
||||
@@ -51,7 +53,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
int truncate_flag = (int) read_bits(ustream,1); // truncate_flag - one CB extra
|
||||
|
||||
int field1packet = 0; // expect Field 1 first
|
||||
if (pattern_flag == 0x00)
|
||||
if (pattern_flag == 0x00)
|
||||
field1packet=1; // expect Field 1 second
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading %d%s DVD CC segments\n",
|
||||
@@ -87,12 +89,12 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
with marker bytes of \xff and \xfe
|
||||
Since markers can be repeated, use pattern as well */
|
||||
if ((data[0]&0xFE) == 0xFE) // Check if valid
|
||||
{
|
||||
{
|
||||
if (data[0]==0xff && j==field1packet)
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(data, sub);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
rcbcount++;
|
||||
}
|
||||
else
|
||||
@@ -118,12 +120,12 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
with marker bytes of \xff and \xfe
|
||||
Since markers can be repeated, use pattern as well */
|
||||
if ((data[0]&0xFE) == 0xFE) // Check if valid
|
||||
{
|
||||
{
|
||||
if (data[0]==0xff && j==field1packet)
|
||||
data[0]=0x04; // Field 1
|
||||
else
|
||||
data[0]=0x05; // Field 2
|
||||
do_cb(data, sub);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
ecbcount++;
|
||||
}
|
||||
else
|
||||
@@ -144,7 +146,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char cc_data[3*31+1]; // Maximum cc_count is 31
|
||||
|
||||
stat_scte20ccheaders++;
|
||||
ctx->stat_scte20ccheaders++;
|
||||
read_bytes(ustream, 2); // "03 01"
|
||||
|
||||
unsigned cc_count = (unsigned int) read_bits(ustream,5);
|
||||
@@ -192,7 +194,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
}
|
||||
}
|
||||
cc_data[cc_count*3]=0xFF;
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n");
|
||||
}
|
||||
@@ -200,31 +202,31 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
}
|
||||
// ReplayTV 4000/5000 caption header - parsing information
|
||||
// derived from CCExtract.bdl
|
||||
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|
||||
|| ud_header[0] == 0x99) //ReplayTV 5000
|
||||
else if ( (ud_header[0] == 0xbb //ReplayTV 4000
|
||||
|| ud_header[0] == 0x99) //ReplayTV 5000
|
||||
&& ud_header[1] == 0x02 )
|
||||
{
|
||||
unsigned char data[3];
|
||||
if (ud_header[0]==0xbb)
|
||||
stat_replay4000headers++;
|
||||
ctx->stat_replay4000headers++;
|
||||
else
|
||||
stat_replay5000headers++;
|
||||
ctx->stat_replay5000headers++;
|
||||
|
||||
read_bytes(ustream, 2); // "BB 02" or "99 02"
|
||||
data[0]=0x05; // Field 2
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data, sub);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
read_bytes(ustream, 2); // Skip "CC 02" for R4000 or "AA 02" for R5000
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data, sub);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
}
|
||||
// HDTV - see A/53 Part 4 (Video)
|
||||
else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) )
|
||||
{
|
||||
stat_hdtv++;
|
||||
ctx->stat_hdtv++;
|
||||
|
||||
read_bytes(ustream, 4); // "47 41 39 34"
|
||||
|
||||
@@ -264,7 +266,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
// Please note we store the current value of the global
|
||||
// fts_now variable (and not get_fts()) as we are going to
|
||||
// re-create the timeline in process_hdcc() (Slightly ugly).
|
||||
store_hdcc(cc_data, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, cc_data, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n");
|
||||
}
|
||||
@@ -285,7 +287,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n");
|
||||
|
||||
stat_dishheaders++;
|
||||
ctx->stat_dishheaders++;
|
||||
|
||||
read_bytes(ustream, 2); // "05 02"
|
||||
|
||||
@@ -344,7 +346,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
|
||||
dishdata[cc_count*3] = 0xFF; // Set end marker
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
|
||||
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
// Ignore 3 (0x0A, followed by two unknown) bytes.
|
||||
break;
|
||||
@@ -360,7 +362,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
cc_count = 2;
|
||||
dishdata[1]=dcd[1];
|
||||
dishdata[2]=dcd[2];
|
||||
|
||||
|
||||
dishdata[3]=0x04; // Field 1
|
||||
dishdata[4]=dcd[3];
|
||||
dishdata[5]=dcd[4];
|
||||
@@ -368,8 +370,8 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "%s", debug_608toASC( dishdata, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
// Ignore 4 (0x020A, followed by two unknown) bytes.
|
||||
break;
|
||||
@@ -379,7 +381,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
// 0 : 0x04
|
||||
// - the following are from previous 0x05 caption header -
|
||||
// 1 : prev dcd[2]
|
||||
// 2-3: prev dcd[3-4]
|
||||
// 2-3: prev dcd[3-4]
|
||||
// 4-5: prev dcd[5-6]
|
||||
dbg_print(CCX_DMT_PARSE, " - %02X pch: %02X %5u %02X:%02X\n",
|
||||
dcd[0], dcd[1],
|
||||
@@ -429,13 +431,13 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
dishdata[4]=dcd[0];
|
||||
dishdata[5]=dcd[1];
|
||||
dishdata[6] = 0xFF; // Set end marker
|
||||
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, ":%s", debug_608toASC( dishdata, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608toASC( dishdata+3, 0) );
|
||||
}
|
||||
|
||||
store_hdcc(dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
|
||||
store_hdcc(ctx, dishdata, cc_count, current_tref, fts_now, sub);
|
||||
|
||||
// Ignore 3 (0x0A, followed by 2 unknown) bytes.
|
||||
break;
|
||||
default:
|
||||
@@ -450,7 +452,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
else if ( !memcmp(ud_header,"\x02\x09", 2 ) )
|
||||
{
|
||||
// Either a documentation or more examples are needed.
|
||||
stat_divicom++;
|
||||
ctx->stat_divicom++;
|
||||
|
||||
unsigned char data[3];
|
||||
|
||||
@@ -460,7 +462,7 @@ int user_data(struct bitstream *ustream, int udtype, struct cc_subtitle *sub)
|
||||
data[0]=0x04; // Field 1
|
||||
data[1]=read_u8(ustream);
|
||||
data[2]=read_u8(ustream);
|
||||
do_cb(data, sub);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
// This is probably incomplete!
|
||||
}
|
||||
else
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <libavutil/log.h>
|
||||
#include <libavutil/error.h>
|
||||
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
struct ffmpeg_ctx
|
||||
{
|
||||
AVFormatContext *ifmt;
|
||||
@@ -74,7 +74,7 @@ void *init_ffmpeg(char *path)
|
||||
|
||||
av_log_set_callback(log_cb);
|
||||
|
||||
ctx = av_malloc(sizeof(*ctx));
|
||||
ctx = av_mallocz(sizeof(*ctx));
|
||||
if(!ctx)
|
||||
{
|
||||
av_log(NULL,AV_LOG_ERROR,"Not enough memory\n");
|
||||
@@ -126,7 +126,7 @@ fail:
|
||||
* @param maxlen length of buffer, where data will be copied
|
||||
* @return number of bytes recieved as data
|
||||
*/
|
||||
int ff_get_ccframe(void *arg,char*data,int maxlen)
|
||||
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen)
|
||||
{
|
||||
struct ffmpeg_ctx *ctx = arg;
|
||||
int len = 0;
|
||||
@@ -19,5 +19,5 @@ void *init_ffmpeg(char *path);
|
||||
* @param maxlen length of buffer, where data will be copied
|
||||
* @return number of bytes recieved as data
|
||||
*/
|
||||
int ff_get_ccframe(void *arg,char*data,int maxlen);
|
||||
int ff_get_ccframe(void *arg, unsigned char*data, int maxlen);
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
long FILEBUFFERSIZE = 1024*1024*16; // 16 Mbytes no less. Minimize number of real read calls()
|
||||
LLONG buffered_read_opt_file (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
@@ -22,22 +23,22 @@ LLONG getfilesize (int in)
|
||||
return length;
|
||||
}
|
||||
|
||||
LLONG gettotalfilessize (void) // -1 if one or more files failed to open
|
||||
LLONG gettotalfilessize (struct lib_ccx_ctx *ctx) // -1 if one or more files failed to open
|
||||
{
|
||||
LLONG ts=0;
|
||||
int h;
|
||||
for (int i=0;i<num_input_files;i++)
|
||||
for (int i=0;i<ctx->num_input_files;i++)
|
||||
{
|
||||
if (0 == strcmp(inputfile[i],"-")) // Skip stdin
|
||||
continue;
|
||||
if (0 == strcmp(ctx->inputfile[i],"-")) // Skip stdin
|
||||
continue;
|
||||
#ifdef _WIN32
|
||||
h=OPEN (inputfile[i],O_RDONLY | O_BINARY);
|
||||
h=OPEN (ctx->inputfile[i],O_RDONLY | O_BINARY);
|
||||
#else
|
||||
h=OPEN (inputfile[i],O_RDONLY);
|
||||
h=OPEN (ctx->inputfile[i],O_RDONLY);
|
||||
#endif
|
||||
if (h==-1)
|
||||
{
|
||||
mprint ("\rUnable to open %s\r\n",inputfile[i]);
|
||||
mprint ("\rUnable to open %s\r\n",ctx->inputfile[i]);
|
||||
return -1;
|
||||
}
|
||||
if (!ccx_options.live_stream)
|
||||
@@ -47,51 +48,53 @@ LLONG gettotalfilessize (void) // -1 if one or more files failed to open
|
||||
return ts;
|
||||
}
|
||||
|
||||
void prepare_for_new_file (void)
|
||||
void prepare_for_new_file (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
// Init per file variables
|
||||
min_pts=0x01FFFFFFFFLL; // 33 bit
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
// Init per file variables
|
||||
min_pts=0x01FFFFFFFFLL; // 33 bit
|
||||
sync_pts=0;
|
||||
pts_set = 0;
|
||||
// inputsize=0; Now responsibility of switch_to_next_file()
|
||||
last_reported_progress=-1;
|
||||
stat_numuserheaders = 0;
|
||||
stat_dvdccheaders = 0;
|
||||
stat_scte20ccheaders = 0;
|
||||
stat_replay5000headers = 0;
|
||||
stat_replay4000headers = 0;
|
||||
stat_dishheaders = 0;
|
||||
stat_hdtv = 0;
|
||||
stat_divicom = 0;
|
||||
ctx->last_reported_progress=-1;
|
||||
ctx->stat_numuserheaders = 0;
|
||||
ctx->stat_dvdccheaders = 0;
|
||||
ctx->stat_scte20ccheaders = 0;
|
||||
ctx->stat_replay5000headers = 0;
|
||||
ctx->stat_replay4000headers = 0;
|
||||
ctx->stat_dishheaders = 0;
|
||||
ctx->stat_hdtv = 0;
|
||||
ctx->stat_divicom = 0;
|
||||
total_frames_count = 0;
|
||||
total_pulldownfields = 0;
|
||||
total_pulldownframes = 0;
|
||||
cc_stats[0]=0; cc_stats[1]=0; cc_stats[2]=0; cc_stats[3]=0;
|
||||
false_pict_header=0;
|
||||
frames_since_last_gop=0;
|
||||
ctx->total_pulldownfields = 0;
|
||||
ctx->total_pulldownframes = 0;
|
||||
dec_ctx->cc_stats[0]=0; dec_ctx->cc_stats[1]=0; dec_ctx->cc_stats[2]=0; dec_ctx->cc_stats[3]=0;
|
||||
ctx->false_pict_header=0;
|
||||
ctx->frames_since_last_gop=0;
|
||||
frames_since_ref_time=0;
|
||||
gop_time.inited=0;
|
||||
first_gop_time.inited=0;
|
||||
gop_rollover=0;
|
||||
printed_gop.inited=0;
|
||||
saw_caption_block=0;
|
||||
past=0;
|
||||
dec_ctx->saw_caption_block=0;
|
||||
ctx->past=0;
|
||||
pts_big_change=0;
|
||||
startbytes_pos=0;
|
||||
startbytes_avail=0;
|
||||
ctx->startbytes_pos=0;
|
||||
ctx->startbytes_avail=0;
|
||||
init_file_buffer();
|
||||
anchor_hdcc(-1);
|
||||
firstcall = 1;
|
||||
}
|
||||
|
||||
/* Close input file if there is one and let the GUI know */
|
||||
void close_input_file (void)
|
||||
void close_input_file (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
if (infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
|
||||
if (ctx->infd!=-1 && ccx_options.input_source==CCX_DS_FILE)
|
||||
{
|
||||
close (infd);
|
||||
infd=-1;
|
||||
activity_input_file_closed();
|
||||
close (ctx->infd);
|
||||
ctx->infd=-1;
|
||||
activity_input_file_closed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,118 +103,120 @@ void close_input_file (void)
|
||||
to 'past' yet. We provide this number to switch_to_next_file() so a final sanity check
|
||||
can be done */
|
||||
|
||||
int switch_to_next_file (LLONG bytesinbuffer)
|
||||
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer)
|
||||
{
|
||||
if (current_file==-1 || !ccx_options.binary_concat)
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
if (ctx->current_file==-1 || !ccx_options.binary_concat)
|
||||
{
|
||||
memset (PIDs_seen,0,65536*sizeof (int));
|
||||
memset (PIDs_programs,0,65536*sizeof (struct PMT_entry *));
|
||||
memset (ctx->PIDs_seen,0,65536*sizeof (int));
|
||||
memset (ctx->PIDs_programs,0,65536*sizeof (struct PMT_entry *));
|
||||
}
|
||||
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
{
|
||||
if (infd!=-1) // Means we had already processed stdin. So we're done.
|
||||
if (ctx->infd!=-1) // Means we had already processed stdin. So we're done.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
print_file_report(ctx);
|
||||
return 0;
|
||||
}
|
||||
infd=0;
|
||||
ctx->infd=0;
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rReading from standard input\n");
|
||||
return 1;
|
||||
}
|
||||
if (ccx_options.input_source==CCX_DS_NETWORK)
|
||||
{
|
||||
if (infd!=-1) // Means we have already bound a socket.
|
||||
if (ctx->infd!=-1) // Means we have already bound a socket.
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
print_file_report(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
|
||||
ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport);
|
||||
return 1;
|
||||
if(infd < 0)
|
||||
if(ctx->infd < 0)
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "socket() failed.");
|
||||
|
||||
}
|
||||
|
||||
if (ccx_options.input_source==CCX_DS_TCP)
|
||||
{
|
||||
if (infd != -1)
|
||||
if (ctx->infd != -1)
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
print_file_report(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
|
||||
ctx->infd = start_tcp_srv(ccx_options.tcpport, ccx_options.tcp_password);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Close current and make sure things are still sane */
|
||||
if (infd!=-1)
|
||||
if (ctx->infd!=-1)
|
||||
{
|
||||
if (ccx_options.print_file_reports)
|
||||
print_file_report();
|
||||
close_input_file ();
|
||||
if (inputsize>0 && ((past+bytesinbuffer) < inputsize) && !processed_enough)
|
||||
print_file_report(ctx);
|
||||
close_input_file (ctx);
|
||||
if (ctx->inputsize>0 && ((ctx->past+bytesinbuffer) < ctx->inputsize) && !dec_ctx->processed_enough)
|
||||
{
|
||||
mprint("\n\n\n\nATTENTION!!!!!!\n");
|
||||
mprint("In switch_to_next_file(): Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
|
||||
inputfile[current_file], current_file, past, inputsize);
|
||||
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->past, ctx->inputsize);
|
||||
}
|
||||
if (ccx_options.binary_concat)
|
||||
{
|
||||
total_past+=inputsize;
|
||||
past=0; // Reset always or at the end we'll have double the size
|
||||
ctx->total_past+=ctx->inputsize;
|
||||
ctx->past=0; // Reset always or at the end we'll have double the size
|
||||
}
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
current_file++;
|
||||
if (current_file>=num_input_files)
|
||||
{
|
||||
ctx->current_file++;
|
||||
if (ctx->current_file>=ctx->num_input_files)
|
||||
break;
|
||||
|
||||
// The following \n keeps the progress percentage from being overwritten.
|
||||
mprint ("\n\r-----------------------------------------------------------------\n");
|
||||
mprint ("\rOpening file: %s\n", inputfile[current_file]);
|
||||
mprint ("\rOpening file: %s\n", ctx->inputfile[ctx->current_file]);
|
||||
#ifdef _WIN32
|
||||
infd=OPEN (inputfile[current_file],O_RDONLY | O_BINARY);
|
||||
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY | O_BINARY);
|
||||
#else
|
||||
infd=OPEN (inputfile[current_file],O_RDONLY);
|
||||
ctx->infd=OPEN (ctx->inputfile[ctx->current_file],O_RDONLY);
|
||||
#endif
|
||||
if (infd == -1)
|
||||
mprint ("\rWarning: Unable to open input file [%s]\n", inputfile[current_file]);
|
||||
if (ctx->infd == -1)
|
||||
mprint ("\rWarning: Unable to open input file [%s]\n", ctx->inputfile[ctx->current_file]);
|
||||
else
|
||||
{
|
||||
activity_input_file_open (inputfile[current_file]);
|
||||
activity_input_file_open (ctx->inputfile[ctx->current_file]);
|
||||
if (!ccx_options.live_stream)
|
||||
{
|
||||
inputsize = getfilesize (infd);
|
||||
ctx->inputsize = getfilesize (ctx->infd);
|
||||
if (!ccx_options.binary_concat)
|
||||
total_inputsize=inputsize;
|
||||
ctx->total_inputsize=ctx->inputsize;
|
||||
}
|
||||
return 1; // Succeeded
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void position_sanity_check ()
|
||||
void position_sanity_check (void)
|
||||
{
|
||||
#ifdef SANITY_CHECK
|
||||
if (in!=-1)
|
||||
{
|
||||
LLONG realpos=LSEEK (in,0,SEEK_CUR);
|
||||
if (realpos!=past-filebuffer_pos+bytesinbuffer)
|
||||
if (realpos!=ctx->past-filebuffer_pos+bytesinbuffer)
|
||||
{
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,past);
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "Position desync, THIS IS A BUG. Real pos =%lld, past=%lld.\n",realpos,ctx->past);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -219,20 +224,20 @@ void position_sanity_check ()
|
||||
int init_file_buffer(void)
|
||||
{
|
||||
filebuffer_start=0;
|
||||
filebuffer_pos=0;
|
||||
filebuffer_pos=0;
|
||||
if (filebuffer==NULL)
|
||||
{
|
||||
filebuffer=(unsigned char *) malloc (FILEBUFFERSIZE);
|
||||
bytesinbuffer=0;
|
||||
}
|
||||
if (filebuffer==NULL)
|
||||
if (filebuffer==NULL)
|
||||
{
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buffered_seek (int offset)
|
||||
void buffered_seek (struct lib_ccx_ctx *ctx, int offset)
|
||||
{
|
||||
position_sanity_check();
|
||||
if (offset<0)
|
||||
@@ -241,17 +246,17 @@ void buffered_seek (int offset)
|
||||
if (filebuffer_pos<0)
|
||||
{
|
||||
// We got into the start buffer (hopefully)
|
||||
if (startbytes_pos+filebuffer_pos < 0)
|
||||
if (ctx->startbytes_pos+filebuffer_pos < 0)
|
||||
{
|
||||
fatal (CCX_COMMON_EXIT_BUG_BUG, "PANIC: Attempt to seek before buffer start, this is a bug!");
|
||||
}
|
||||
startbytes_pos+=filebuffer_pos;
|
||||
ctx->startbytes_pos+=filebuffer_pos;
|
||||
filebuffer_pos=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read_opt (NULL, offset);
|
||||
buffered_read_opt (ctx, NULL, offset);
|
||||
position_sanity_check();
|
||||
}
|
||||
}
|
||||
@@ -260,7 +265,7 @@ void sleepandchecktimeout (time_t start)
|
||||
{
|
||||
if (ccx_options.input_source==CCX_DS_STDIN)
|
||||
{
|
||||
// CFS: Not 100% sure about this. Fine for files, not so sure what happens if stdin is
|
||||
// CFS: Not 100% sure about this. Fine for files, not so sure what happens if stdin is
|
||||
// real time input from hardware.
|
||||
sleep_secs (1);
|
||||
ccx_options.live_stream=0;
|
||||
@@ -273,7 +278,7 @@ void sleepandchecktimeout (time_t start)
|
||||
return;
|
||||
}
|
||||
if (time(NULL)>start+ccx_options.live_stream) // More than live_stream seconds elapsed. No more live
|
||||
ccx_options.live_stream=0;
|
||||
ccx_options.live_stream=0;
|
||||
else
|
||||
sleep_secs(1);
|
||||
}
|
||||
@@ -282,7 +287,7 @@ void return_to_buffer (unsigned char *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes == filebuffer_pos)
|
||||
{
|
||||
// Usually we're just going back in the buffer and memcpy would be
|
||||
// Usually we're just going back in the buffer and memcpy would be
|
||||
// unnecessary, but we do it in case we intentionally messed with the
|
||||
// buffer
|
||||
memcpy (filebuffer, buffer, bytes);
|
||||
@@ -295,7 +300,7 @@ void return_to_buffer (unsigned char *buffer, unsigned int bytes)
|
||||
// we're never here in ccextractor.
|
||||
memmove (filebuffer,filebuffer+filebuffer_pos,bytesinbuffer-filebuffer_pos);
|
||||
bytesinbuffer-=filebuffer_pos;
|
||||
bytesinbuffer=0;
|
||||
bytesinbuffer=0;
|
||||
filebuffer_pos=0;
|
||||
}
|
||||
|
||||
@@ -306,33 +311,33 @@ void return_to_buffer (unsigned char *buffer, unsigned int bytes)
|
||||
bytesinbuffer+=bytes;
|
||||
}
|
||||
|
||||
LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes)
|
||||
{
|
||||
LLONG copied=0;
|
||||
position_sanity_check();
|
||||
time_t seconds=0;
|
||||
if (ccx_options.live_stream>0)
|
||||
time (&seconds);
|
||||
if (ccx_options.live_stream>0)
|
||||
time (&seconds);
|
||||
if (ccx_options.buffer_input || filebuffer_pos<bytesinbuffer)
|
||||
{
|
||||
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
|
||||
int eof = (infd==-1);
|
||||
{
|
||||
// Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1;
|
||||
int eof = (ctx->infd==-1);
|
||||
|
||||
while ((!eof || ccx_options.live_stream) && bytes)
|
||||
{
|
||||
{
|
||||
if (eof)
|
||||
{
|
||||
// No more data available inmediately, we sleep a while to give time
|
||||
// for the data to come up
|
||||
// for the data to come up
|
||||
sleepandchecktimeout (seconds);
|
||||
}
|
||||
size_t ready = bytesinbuffer-filebuffer_pos;
|
||||
size_t ready = bytesinbuffer-filebuffer_pos;
|
||||
if (ready==0) // We really need to read more
|
||||
{
|
||||
if (!ccx_options.buffer_input)
|
||||
{
|
||||
// We got in the buffering code because of the initial buffer for
|
||||
// detection stuff. However we don't want more buffering so
|
||||
// detection stuff. However we don't want more buffering so
|
||||
// we do the rest directly on the final buffer.
|
||||
int i;
|
||||
do
|
||||
@@ -341,7 +346,7 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
// buffered - if here, then it must be files.
|
||||
if (buffer!=NULL) // Read
|
||||
{
|
||||
i=read (infd,buffer,bytes);
|
||||
i=read (ctx->infd,buffer,bytes);
|
||||
if( i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
buffer+=i;
|
||||
@@ -349,10 +354,10 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
else // Seek
|
||||
{
|
||||
LLONG op, np;
|
||||
op =LSEEK (infd,0,SEEK_CUR); // Get current pos
|
||||
op =LSEEK (ctx->infd,0,SEEK_CUR); // Get current pos
|
||||
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
|
||||
return 0;
|
||||
np =LSEEK (infd,bytes,SEEK_CUR); // Pos after moving
|
||||
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
|
||||
i=(int) (np-op);
|
||||
}
|
||||
if (i==0 && ccx_options.live_stream)
|
||||
@@ -372,28 +377,28 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
copied+=i;
|
||||
bytes-=i;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
while ((i || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(copied))) && bytes);
|
||||
return copied;
|
||||
while ((i || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))) && bytes);
|
||||
return copied;
|
||||
}
|
||||
// Keep the last 8 bytes, so we have a guaranteed
|
||||
// Keep the last 8 bytes, so we have a guaranteed
|
||||
// working seek (-8) - needed by mythtv.
|
||||
int keep = bytesinbuffer > 8 ? 8 : bytesinbuffer;
|
||||
memmove (filebuffer,filebuffer+(FILEBUFFERSIZE-keep),keep);
|
||||
int i;
|
||||
if (ccx_options.input_source==CCX_DS_FILE || ccx_options.input_source==CCX_DS_STDIN)
|
||||
i=read (infd, filebuffer+keep,FILEBUFFERSIZE-keep);
|
||||
i=read (ctx->infd, filebuffer+keep,FILEBUFFERSIZE-keep);
|
||||
else
|
||||
i = recvfrom(infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,NULL,NULL);
|
||||
i = recvfrom(ctx->infd,(char *) filebuffer+keep,FILEBUFFERSIZE-keep,0,NULL,NULL);
|
||||
if (i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input stream!\n");
|
||||
if (i==0)
|
||||
{
|
||||
/* If live stream, don't try to switch - acknowledge eof here as it won't
|
||||
cause a loop end */
|
||||
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(copied)))
|
||||
if (ccx_options.live_stream || !(ccx_options.binary_concat && switch_to_next_file(ctx, copied)))
|
||||
eof=1;
|
||||
}
|
||||
filebuffer_pos=keep;
|
||||
@@ -403,27 +408,27 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
int copy = (int) (ready>=bytes ? bytes:ready);
|
||||
if (copy)
|
||||
{
|
||||
if (buffer!=NULL)
|
||||
if (buffer!=NULL)
|
||||
{
|
||||
memcpy (buffer, filebuffer+filebuffer_pos, copy);
|
||||
memcpy (buffer, filebuffer+filebuffer_pos, copy);
|
||||
buffer+=copy;
|
||||
}
|
||||
filebuffer_pos+=copy;
|
||||
filebuffer_pos+=copy;
|
||||
bytes-=copy;
|
||||
copied+=copy;
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
else // Read without buffering
|
||||
else // Read without buffering
|
||||
{
|
||||
|
||||
|
||||
if (buffer!=NULL)
|
||||
{
|
||||
int i;
|
||||
while (bytes>0 && infd!=-1 &&
|
||||
((i=read(infd,buffer,bytes))!=0 || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(copied))))
|
||||
while (bytes>0 && ctx->infd!=-1 &&
|
||||
((i=read(ctx->infd,buffer,bytes))!=0 || ccx_options.live_stream ||
|
||||
(ccx_options.binary_concat && switch_to_next_file(ctx, copied))))
|
||||
{
|
||||
if( i == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
@@ -440,13 +445,13 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
}
|
||||
// return fread(buffer,1,bytes,in);
|
||||
//return FSEEK (in,bytes,SEEK_CUR);
|
||||
while (bytes!=0 && infd!=-1)
|
||||
while (bytes!=0 && ctx->infd!=-1)
|
||||
{
|
||||
LLONG op, np;
|
||||
op =LSEEK (infd,0,SEEK_CUR); // Get current pos
|
||||
op =LSEEK (ctx->infd,0,SEEK_CUR); // Get current pos
|
||||
if (op+bytes<0) // Would mean moving beyond start of file: Not supported
|
||||
return 0;
|
||||
np =LSEEK (infd,bytes,SEEK_CUR); // Pos after moving
|
||||
np =LSEEK (ctx->infd,bytes,SEEK_CUR); // Pos after moving
|
||||
copied=copied+(np-op);
|
||||
bytes=bytes-(unsigned int) copied;
|
||||
if (copied==0)
|
||||
@@ -456,7 +461,7 @@ LLONG buffered_read_opt (unsigned char *buffer, unsigned int bytes)
|
||||
else
|
||||
{
|
||||
if (ccx_options.binary_concat)
|
||||
switch_to_next_file(0);
|
||||
switch_to_next_file(ctx, 0);
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
@@ -25,7 +26,7 @@ int end_of_file=0; // End of file?
|
||||
|
||||
|
||||
const static unsigned char DO_NOTHING[] = {0x80, 0x80};
|
||||
LLONG inbuf = 0; // Number of bytes loaded in buffer
|
||||
LLONG inbuf = 0; // Number of bytes loaded in buffer
|
||||
int ccx_bufferdatatype = CCX_PES; // Can be RAW, PES, H264 or Hauppage
|
||||
|
||||
// Remember if the last header was valid. Used to suppress too much output
|
||||
@@ -36,12 +37,10 @@ unsigned char *filebuffer;
|
||||
LLONG filebuffer_start; // Position of buffer start relative to file
|
||||
int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
extern void *cxx_dvb_context;
|
||||
|
||||
LLONG process_raw_with_field (struct cc_subtitle *sub);
|
||||
extern void *ccx_dvb_context;
|
||||
|
||||
// Program stream specific data grabber
|
||||
LLONG ps_getmoredata(void)
|
||||
LLONG ps_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int enough = 0;
|
||||
int payload_read = 0;
|
||||
@@ -52,18 +51,18 @@ LLONG ps_getmoredata(void)
|
||||
int falsepack=0;
|
||||
|
||||
// Read and return the next video PES payload
|
||||
do
|
||||
do
|
||||
{
|
||||
if (BUFSIZE-inbuf<500)
|
||||
if (BUFSIZE-inbuf<500)
|
||||
{
|
||||
mprint("Less than 500 left\n");
|
||||
enough=1; // Stop when less than 500 bytes are left in buffer
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
buffered_read(nextheader,6);
|
||||
past+=result;
|
||||
if (result!=6)
|
||||
buffered_read(ctx, nextheader, 6);
|
||||
ctx->past+=result;
|
||||
if (result!=6)
|
||||
{
|
||||
// Consider this the end of the show.
|
||||
end_of_file=1;
|
||||
@@ -72,7 +71,7 @@ LLONG ps_getmoredata(void)
|
||||
|
||||
// Search for a header that is not a picture header (nextheader[3]!=0x00)
|
||||
while ( !(nextheader[0]==0x00 && nextheader[1]==0x00
|
||||
&& nextheader[2]==0x01 && nextheader[3]!=0x00) )
|
||||
&& nextheader[2]==0x01 && nextheader[3]!=0x00) )
|
||||
{
|
||||
if( !strangeheader )
|
||||
{
|
||||
@@ -93,10 +92,10 @@ LLONG ps_getmoredata(void)
|
||||
{
|
||||
int atpos = newheader-nextheader;
|
||||
|
||||
memmove (nextheader,newheader,(size_t)(hlen-atpos));
|
||||
buffered_read(nextheader+(hlen-atpos),atpos);
|
||||
past+=result;
|
||||
if (result!=atpos)
|
||||
memmove (nextheader,newheader,(size_t)(hlen-atpos));
|
||||
buffered_read(ctx, nextheader+(hlen-atpos),atpos);
|
||||
ctx->past+=result;
|
||||
if (result!=atpos)
|
||||
{
|
||||
end_of_file=1;
|
||||
break;
|
||||
@@ -104,9 +103,9 @@ LLONG ps_getmoredata(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
buffered_read(nextheader,hlen);
|
||||
past+=result;
|
||||
if (result!=hlen)
|
||||
buffered_read(ctx, nextheader, hlen);
|
||||
ctx->past+=result;
|
||||
if (result!=hlen)
|
||||
{
|
||||
end_of_file=1;
|
||||
break;
|
||||
@@ -122,12 +121,12 @@ LLONG ps_getmoredata(void)
|
||||
strangeheader=0;
|
||||
|
||||
// PACK header
|
||||
if ( nextheader[3]==0xBA)
|
||||
if ( nextheader[3]==0xBA)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "PACK header\n");
|
||||
buffered_read(nextheader+6,8);
|
||||
past+=result;
|
||||
if (result!=8)
|
||||
buffered_read(ctx, nextheader+6,8);
|
||||
ctx->past+=result;
|
||||
if (result!=8)
|
||||
{
|
||||
// Consider this the end of the show.
|
||||
end_of_file=1;
|
||||
@@ -136,7 +135,7 @@ LLONG ps_getmoredata(void)
|
||||
|
||||
if ( (nextheader[4]&0xC4)!=0x44 || !(nextheader[6]&0x04)
|
||||
|| !(nextheader[8]&0x04) || !(nextheader[9]&0x01)
|
||||
|| (nextheader[12]&0x03)!=0x03 )
|
||||
|| (nextheader[12]&0x03)!=0x03 )
|
||||
{
|
||||
// broken pack header
|
||||
falsepack=1;
|
||||
@@ -144,20 +143,20 @@ LLONG ps_getmoredata(void)
|
||||
// We don't need SCR/SCR_ext
|
||||
int stufflen=nextheader[13]&0x07;
|
||||
|
||||
if (falsepack)
|
||||
if (falsepack)
|
||||
{
|
||||
mprint ("Warning: Defective Pack header\n");
|
||||
}
|
||||
|
||||
// If not defect, load stuffing
|
||||
buffered_skip ((int) stufflen);
|
||||
past+=stufflen;
|
||||
buffered_skip (ctx, (int) stufflen);
|
||||
ctx->past+=stufflen;
|
||||
// fake a result value as something was skipped
|
||||
result=1;
|
||||
continue;
|
||||
}
|
||||
// Some PES stream
|
||||
else if (nextheader[3]>=0xBB && nextheader[3]<=0xDF)
|
||||
else if (nextheader[3]>=0xBB && nextheader[3]<=0xDF)
|
||||
{
|
||||
// System header
|
||||
// nextheader[3]==0xBB
|
||||
@@ -182,18 +181,18 @@ LLONG ps_getmoredata(void)
|
||||
}
|
||||
|
||||
// Skip over it
|
||||
buffered_skip ((int) headerlen);
|
||||
past+=headerlen;
|
||||
buffered_skip (ctx, (int) headerlen);
|
||||
ctx->past+=headerlen;
|
||||
// fake a result value as something was skipped
|
||||
result=1;
|
||||
|
||||
continue;
|
||||
}
|
||||
// Read the next video PES
|
||||
else if ((nextheader[3]&0xf0)==0xe0)
|
||||
else if ((nextheader[3]&0xf0)==0xe0)
|
||||
{
|
||||
int hlen; // Dummy variable, unused
|
||||
int peslen = read_video_pes_header(nextheader, &hlen, 0);
|
||||
int peslen = read_video_pes_header(ctx, nextheader, &hlen, 0);
|
||||
if (peslen < 0)
|
||||
{
|
||||
end_of_file=1;
|
||||
@@ -214,8 +213,8 @@ LLONG ps_getmoredata(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
buffered_read (buffer+inbuf,want);
|
||||
past=past+result;
|
||||
buffered_read (ctx, ctx->buffer+inbuf, want);
|
||||
ctx->past=ctx->past+result;
|
||||
if (result>0) {
|
||||
payload_read+=(int) result;
|
||||
}
|
||||
@@ -233,7 +232,7 @@ LLONG ps_getmoredata(void)
|
||||
strangeheader=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (result!=0 && !enough && BUFSIZE!=inbuf);
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "PES data read: %d\n", payload_read);
|
||||
@@ -243,17 +242,17 @@ LLONG ps_getmoredata(void)
|
||||
|
||||
|
||||
// Returns number of bytes read, or zero for EOF
|
||||
LLONG general_getmoredata(void)
|
||||
LLONG general_getmoredata(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int bytesread = 0;
|
||||
int want;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
want = (int) (BUFSIZE-inbuf);
|
||||
buffered_read (buffer+inbuf,want); // This is a macro.
|
||||
buffered_read (ctx, ctx->buffer+inbuf,want); // This is a macro.
|
||||
// 'result' HAS the number of bytes read
|
||||
past=past+result;
|
||||
ctx->past=ctx->past+result;
|
||||
inbuf+=result;
|
||||
bytesread+=(int) result;
|
||||
} while (result!=0 && result!=want);
|
||||
@@ -262,12 +261,12 @@ LLONG general_getmoredata(void)
|
||||
|
||||
#ifdef WTV_DEBUG
|
||||
// Hexadecimal dump process
|
||||
void processhex (char *filename)
|
||||
void processhex (struct lib_ccx_ctx *ctx, char *filename)
|
||||
{
|
||||
size_t max=(size_t) inputsize+1; // Enough for the whole thing. Hex dumps are small so we can be lazy here
|
||||
size_t max=(size_t) ctx->inputsize+1; // Enough for the whole thing. Hex dumps are small so we can be lazy here
|
||||
char *line=(char *) malloc (max);
|
||||
/* const char *mpeg_header="00 00 01 b2 43 43 01 f8 "; // Always present */
|
||||
FILE *fr = fopen (filename, "rt");
|
||||
FILE *fr = fopen (filename, "rt");
|
||||
unsigned char *bytes=NULL;
|
||||
unsigned byte_count=0;
|
||||
int warning_shown=0;
|
||||
@@ -275,7 +274,7 @@ void processhex (char *filename)
|
||||
{
|
||||
char *c1, *c2=NULL; // Positions for first and second colons
|
||||
/* int len; */
|
||||
long timing;
|
||||
long timing;
|
||||
if (line[0]==';') // Skip comments
|
||||
continue;
|
||||
c1=strchr (line,':');
|
||||
@@ -286,7 +285,7 @@ void processhex (char *filename)
|
||||
*c2=0;
|
||||
/* len=atoi (line); */
|
||||
timing=atol (c1+2)*(MPEG_CLOCK_FREQ/1000);
|
||||
current_pts=timing;
|
||||
current_pts=timing;
|
||||
if (pts_set==0)
|
||||
pts_set=1;
|
||||
set_fts();
|
||||
@@ -295,10 +294,10 @@ void processhex (char *filename)
|
||||
if (strlen (c2)==8)
|
||||
{
|
||||
unsigned char high1=c2[1];
|
||||
unsigned char low1=c2[2];
|
||||
unsigned char low1=c2[2];
|
||||
int value1=hex2int (high1,low1);
|
||||
unsigned char high2=c2[4];
|
||||
unsigned char low2=c2[5];
|
||||
unsigned char low2=c2[5];
|
||||
int value2=hex2int (high2,low2);
|
||||
buffer[0]=value1;
|
||||
buffer[1]=value2;
|
||||
@@ -322,7 +321,7 @@ void processhex (char *filename)
|
||||
// OK, seems like a decent chunk of CCdata.
|
||||
c2+=strlen (mpeg_header);
|
||||
*/
|
||||
byte_count=strlen (c2)/3;
|
||||
byte_count=strlen (c2)/3;
|
||||
/*
|
||||
if (atoi (line)!=byte_count+strlen (mpeg_header)/3) // Number of bytes reported don't match actual contents
|
||||
continue;
|
||||
@@ -331,42 +330,42 @@ void processhex (char *filename)
|
||||
continue;
|
||||
if (!byte_count) // Nothing to get from this line except timing info, already done.
|
||||
continue;
|
||||
bytes=(unsigned char *) malloc (byte_count);
|
||||
bytes=(unsigned char *) malloc (byte_count);
|
||||
if (!bytes)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Out of memory.\n");
|
||||
unsigned char *bytes=(unsigned char *) malloc (byte_count);
|
||||
for (unsigned i=0;i<byte_count;i++)
|
||||
{
|
||||
unsigned char high=c2[0];
|
||||
unsigned char low=c2[1];
|
||||
unsigned char low=c2[1];
|
||||
int value=hex2int (high,low);
|
||||
if (value==-1)
|
||||
fatal (EXIT_FAILURE, "Incorrect format, unexpected non-hex string.");
|
||||
bytes[i]=value;
|
||||
c2+=3;
|
||||
}
|
||||
memcpy (buffer, bytes, byte_count);
|
||||
memcpy (ctx->buffer, bytes, byte_count);
|
||||
inbuf=byte_count;
|
||||
process_raw();
|
||||
continue;
|
||||
// New wtv format, everything else hopefully obsolete
|
||||
|
||||
int ok=0; // Were we able to process the line?
|
||||
// Attempt to detect how the data is encoded.
|
||||
// Attempt to detect how the data is encoded.
|
||||
// Case 1 (seen in all elderman's samples):
|
||||
// 18 : 467 : 00 00 01 b2 43 43 01 f8 03 42 ff fd 54 80 fc 94 2c ff
|
||||
// Always 03 after header, then something unknown (seen 42, 43, c2, c3...),
|
||||
// 18 : 467 : 00 00 01 b2 43 43 01 f8 03 42 ff fd 54 80 fc 94 2c ff
|
||||
// Always 03 after header, then something unknown (seen 42, 43, c2, c3...),
|
||||
// then ff, then data with field info, and terminated with ff.
|
||||
if (byte_count>3 && bytes[0]==0x03 &&
|
||||
bytes[2]==0xff && bytes[byte_count-1]==0xff)
|
||||
{
|
||||
{
|
||||
ok=1;
|
||||
for (unsigned i=3; i<byte_count-2; i+=3)
|
||||
{
|
||||
inbuf=3;
|
||||
buffer[0]=bytes[i];
|
||||
buffer[1]=bytes[i+1];
|
||||
buffer[2]=bytes[i+2];
|
||||
ctx->buffer[0]=bytes[i];
|
||||
ctx->buffer[1]=bytes[i+1];
|
||||
ctx->buffer[2]=bytes[i+2];
|
||||
process_raw_with_field();
|
||||
}
|
||||
}
|
||||
@@ -378,18 +377,18 @@ void processhex (char *filename)
|
||||
/* unsigned extra_field_flag=magic&1; */
|
||||
unsigned caption_count=((magic>>1)&0x1F);
|
||||
unsigned filler=((magic>>6)&1);
|
||||
/* unsigned pattern=((magic>>7)&1); */
|
||||
/* unsigned pattern=((magic>>7)&1); */
|
||||
int always_ff=1;
|
||||
int current_field=0;
|
||||
int current_field=0;
|
||||
if (filler==0 && caption_count*6==byte_count-1) // Note that we are ignoring the extra field for now...
|
||||
{
|
||||
ok=1;
|
||||
ok=1;
|
||||
for (unsigned i=1; i<byte_count-2; i+=3)
|
||||
if (bytes[i]!=0xff)
|
||||
{
|
||||
// If we only find FF in the first byte then either there's only field 1 data, OR
|
||||
// there's alternating field 1 and field 2 data. Don't know how to tell apart. For now
|
||||
// let's assume that always FF means alternating.
|
||||
// let's assume that always FF means alternating.
|
||||
always_ff=0;
|
||||
break;
|
||||
}
|
||||
@@ -399,14 +398,14 @@ void processhex (char *filename)
|
||||
inbuf=3;
|
||||
if (always_ff) // Try to tell apart the fields based on the pattern field.
|
||||
{
|
||||
buffer[0]=current_field | 4; // | 4 to enable the 'valid' bit
|
||||
current_field = !current_field;
|
||||
ctx->buffer[0]=current_field | 4; // | 4 to enable the 'valid' bit
|
||||
current_field = !current_field;
|
||||
}
|
||||
else
|
||||
buffer[0]=bytes[i];
|
||||
ctx->buffer[0]=bytes[i];
|
||||
|
||||
buffer[1]=bytes[i+1];
|
||||
buffer[2]=bytes[i+2];
|
||||
ctx->buffer[1]=bytes[i+1];
|
||||
ctx->buffer[2]=bytes[i+2];
|
||||
process_raw_with_field();
|
||||
}
|
||||
}
|
||||
@@ -418,16 +417,16 @@ void processhex (char *filename)
|
||||
}
|
||||
free (bytes);
|
||||
}
|
||||
fclose(fr);
|
||||
fclose(fr);
|
||||
}
|
||||
#endif
|
||||
// Raw file process
|
||||
void raw_loop (void *enc_ctx)
|
||||
void raw_loop (struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
{
|
||||
LLONG got;
|
||||
LLONG processed;
|
||||
struct cc_subtitle dec_sub;
|
||||
|
||||
|
||||
current_pts = 90; // Pick a valid PTS time
|
||||
pts_set = 1;
|
||||
set_fts(); // Now set the FTS related variables
|
||||
@@ -441,12 +440,12 @@ void raw_loop (void *enc_ctx)
|
||||
{
|
||||
inbuf=0;
|
||||
|
||||
got=general_getmoredata();
|
||||
got = general_getmoredata(ctx);
|
||||
|
||||
if (got == 0) // Shortcircuit if we got nothing to process
|
||||
break;
|
||||
|
||||
processed=process_raw(&dec_sub);
|
||||
processed=process_raw(ctx, &dec_sub);
|
||||
if (dec_sub.got_output)
|
||||
{
|
||||
encode_sub(enc_ctx,&dec_sub);
|
||||
@@ -462,10 +461,10 @@ void raw_loop (void *enc_ctx)
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s incl. %d CB\n",
|
||||
print_mstime(get_fts()), ccblocks);
|
||||
|
||||
|
||||
if (processed<got)
|
||||
{
|
||||
mprint ("BUG BUG\n");
|
||||
mprint ("BUG BUG\n");
|
||||
}
|
||||
}
|
||||
while (inbuf);
|
||||
@@ -473,79 +472,85 @@ void raw_loop (void *enc_ctx)
|
||||
|
||||
/* Process inbuf bytes in buffer holding raw caption data (three byte packets, the first being the field).
|
||||
* The number of processed bytes is returned. */
|
||||
LLONG process_raw_with_field ( struct cc_subtitle *sub)
|
||||
LLONG process_raw_with_field (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char data[3];
|
||||
data[0]=0x04; // Field 1
|
||||
current_field=1;
|
||||
unsigned char data[3];
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
data[0]=0x04; // Field 1
|
||||
current_field=1;
|
||||
|
||||
for (unsigned long i=0; i<inbuf; i=i+3)
|
||||
{
|
||||
if ( !saw_caption_block && *(buffer+i)==0xff && *(buffer+i+1)==0xff)
|
||||
{
|
||||
// Skip broadcast header
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0]=buffer[i];
|
||||
data[1]=buffer[i+1];
|
||||
data[2]=buffer[i+2];
|
||||
for (unsigned long i=0; i<inbuf; i=i+3)
|
||||
{
|
||||
if ( !dec_ctx->saw_caption_block && *(ctx->buffer+i)==0xff && *(ctx->buffer+i+1)==0xff)
|
||||
{
|
||||
// Skip broadcast header
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0]=ctx->buffer[i];
|
||||
data[1]=ctx->buffer[i+1];
|
||||
data[2]=ctx->buffer[i+2];
|
||||
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(data, sub);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(dec_ctx, data, sub);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
|
||||
/* Process inbuf bytes in buffer holding raw caption data (two byte packets).
|
||||
* The number of processed bytes is returned. */
|
||||
LLONG process_raw (struct cc_subtitle *sub)
|
||||
LLONG process_raw (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
unsigned char data[3];
|
||||
unsigned char data[3];
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
data[0]=0x04; // Field 1
|
||||
current_field=1;
|
||||
|
||||
for (unsigned long i=0; i<inbuf; i=i+2)
|
||||
{
|
||||
if ( !saw_caption_block && *(buffer+i)==0xff && *(buffer+i+1)==0xff)
|
||||
if ( !dec_ctx->saw_caption_block && *(ctx->buffer+i)==0xff && *(ctx->buffer+i+1)==0xff)
|
||||
{
|
||||
// Skip broadcast header
|
||||
// Skip broadcast header
|
||||
}
|
||||
else
|
||||
{
|
||||
data[1]=buffer[i];
|
||||
data[2]=buffer[i+1];
|
||||
data[1]=ctx->buffer[i];
|
||||
data[2]=ctx->buffer[i+1];
|
||||
|
||||
// do_cb increases the cb_field1 counter so that get_fts()
|
||||
// is correct.
|
||||
do_cb(data,sub);
|
||||
do_cb(dec_ctx, data, sub);
|
||||
}
|
||||
}
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
|
||||
void general_loop(void *enc_ctx)
|
||||
void general_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
{
|
||||
LLONG overlap=0;
|
||||
LLONG pos = 0; /* Current position in buffer */
|
||||
LLONG overlap=0;
|
||||
LLONG pos = 0; /* Current position in buffer */
|
||||
struct cc_subtitle dec_sub;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
inbuf = 0; // No data yet
|
||||
|
||||
end_of_file = 0;
|
||||
current_picture_coding_type = CCX_FRAME_TYPE_RESET_OR_UNKNOWN;
|
||||
memset(&dec_sub, 0,sizeof(dec_sub));
|
||||
while (!end_of_file && !processed_enough)
|
||||
while (!end_of_file && !dec_ctx->processed_enough)
|
||||
{
|
||||
/* Get rid of the bytes we already processed */
|
||||
overlap=inbuf-pos;
|
||||
/* Get rid of the bytes we already processed */
|
||||
overlap=inbuf-pos;
|
||||
if ( pos != 0 ) {
|
||||
// Only when needed as memmove has been seen crashing
|
||||
// for dest==source and n >0
|
||||
memmove (buffer,buffer+pos,(size_t) (inbuf-pos));
|
||||
memmove (ctx->buffer,ctx->buffer+pos,(size_t) (inbuf-pos));
|
||||
inbuf-=pos;
|
||||
}
|
||||
pos = 0;
|
||||
@@ -553,35 +558,35 @@ void general_loop(void *enc_ctx)
|
||||
// GET MORE DATA IN BUFFER
|
||||
LLONG i;
|
||||
position_sanity_check();
|
||||
switch (stream_mode)
|
||||
switch (ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
i = general_getmoredata();
|
||||
i = general_getmoredata(ctx);
|
||||
break;
|
||||
case CCX_SM_TRANSPORT:
|
||||
i = ts_getmoredata();
|
||||
i = ts_getmoredata(ctx);
|
||||
break;
|
||||
case CCX_SM_PROGRAM:
|
||||
i = ps_getmoredata();
|
||||
i = ps_getmoredata(ctx);
|
||||
break;
|
||||
case CCX_SM_ASF:
|
||||
i = asf_getmoredata();
|
||||
i = asf_getmoredata(ctx);
|
||||
break;
|
||||
case CCX_SM_WTV:
|
||||
i = wtv_getmoredata();
|
||||
i = wtv_getmoredata(ctx);
|
||||
break;
|
||||
default:
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Impossible stream_mode");
|
||||
}
|
||||
|
||||
position_sanity_check();
|
||||
if (fh_out_elementarystream!=NULL)
|
||||
fwrite (buffer+overlap,1,(size_t) (inbuf-overlap),fh_out_elementarystream);
|
||||
if (ctx->fh_out_elementarystream!=NULL)
|
||||
fwrite (ctx->buffer+overlap,1,(size_t) (inbuf-overlap),ctx->fh_out_elementarystream);
|
||||
|
||||
if (i==0)
|
||||
{
|
||||
end_of_file = 1;
|
||||
memset (buffer+inbuf, 0, (size_t) (BUFSIZE-inbuf)); /* Clear buffer at the end */
|
||||
memset (ctx->buffer+inbuf, 0, (size_t) (BUFSIZE-inbuf)); /* Clear buffer at the end */
|
||||
}
|
||||
|
||||
if (inbuf == 0)
|
||||
@@ -596,25 +601,25 @@ void general_loop(void *enc_ctx)
|
||||
|
||||
if (ccx_options.hauppauge_mode)
|
||||
{
|
||||
got = process_raw_with_field(&dec_sub);
|
||||
got = process_raw_with_field(ctx, &dec_sub);
|
||||
if (pts_set)
|
||||
set_fts(); // Try to fix timing from TS data
|
||||
}
|
||||
else if(ccx_bufferdatatype == CCX_DVB_SUBTITLE)
|
||||
{
|
||||
dvbsub_decode(cxx_dvb_context, buffer + 2, inbuf, &dec_sub);
|
||||
dvbsub_decode(ccx_dvb_context, ctx->buffer + 2, inbuf, &dec_sub);
|
||||
set_fts();
|
||||
got = inbuf;
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_PES)
|
||||
{
|
||||
got = process_m2v (buffer, inbuf,&dec_sub);
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_PES)
|
||||
{
|
||||
got = process_m2v (ctx, ctx->buffer, inbuf,&dec_sub);
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_TELETEXT)
|
||||
{
|
||||
// Dispatch to Petr Kutalek 's telxcc.
|
||||
tlt_process_pes_packet (buffer, (uint16_t) inbuf);
|
||||
got = inbuf;
|
||||
tlt_process_pes_packet (ctx, ctx->buffer, (uint16_t) inbuf);
|
||||
got = inbuf;
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_PRIVATE_MPEG2_CC)
|
||||
{
|
||||
@@ -656,18 +661,18 @@ void general_loop(void *enc_ctx)
|
||||
(unsigned) (current_pts));
|
||||
dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime(get_fts()));
|
||||
|
||||
got = process_raw(&dec_sub);
|
||||
got = process_raw(ctx, &dec_sub);
|
||||
}
|
||||
else if (ccx_bufferdatatype == CCX_H264) // H.264 data from TS file
|
||||
{
|
||||
got = process_avc(buffer, inbuf,&dec_sub);
|
||||
got = process_avc(ctx, ctx->buffer, inbuf,&dec_sub);
|
||||
}
|
||||
else
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Unknown data type!");
|
||||
|
||||
if (got>inbuf)
|
||||
{
|
||||
mprint ("BUG BUG\n");
|
||||
mprint ("BUG BUG\n");
|
||||
}
|
||||
pos+=got;
|
||||
|
||||
@@ -675,25 +680,25 @@ void general_loop(void *enc_ctx)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int th=cur_sec/10;
|
||||
if (last_reported_progress!=th)
|
||||
if (ctx->last_reported_progress!=th)
|
||||
{
|
||||
activity_progress (-1,cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = th;
|
||||
ctx->last_reported_progress = th;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (total_inputsize>255) // Less than 255 leads to division by zero below.
|
||||
if (ctx->total_inputsize>255) // Less than 255 leads to division by zero below.
|
||||
{
|
||||
int progress = (int) ((((total_past+past)>>8)*100)/(total_inputsize>>8));
|
||||
if (last_reported_progress != progress)
|
||||
int progress = (int) ((((ctx->total_past+ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
LLONG t=get_fts();
|
||||
if (!t && global_timestamp_inited)
|
||||
t=global_timestamp-min_global_timestamp;
|
||||
if (!t && ctx->global_timestamp_inited)
|
||||
t=ctx->global_timestamp-ctx->min_global_timestamp;
|
||||
int cur_sec = (int) (t / 1000);
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = progress;
|
||||
activity_progress(progress, cur_sec/60, cur_sec%60);
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -706,13 +711,13 @@ void general_loop(void *enc_ctx)
|
||||
}
|
||||
// Flush remaining HD captions
|
||||
if (has_ccdata_buffered)
|
||||
process_hdcc(&dec_sub);
|
||||
process_hdcc(ctx, &dec_sub);
|
||||
|
||||
if (total_past!=total_inputsize && ccx_options.binary_concat && !processed_enough)
|
||||
if (ctx->total_past!=ctx->total_inputsize && ccx_options.binary_concat && !dec_ctx->processed_enough)
|
||||
{
|
||||
mprint("\n\n\n\nATTENTION!!!!!!\n");
|
||||
mprint("Processing of %s %d ended prematurely %lld < %lld, please send bug report.\n\n",
|
||||
inputfile[current_file], current_file, past, inputsize);
|
||||
ctx->inputfile[ctx->current_file], ctx->current_file, ctx->past, ctx->inputsize);
|
||||
}
|
||||
mprint ("\nNumber of NAL_type_7: %ld\n",num_nal_unit_type_7);
|
||||
mprint ("Number of VCL_HRD: %ld\n",num_vcl_hrd);
|
||||
@@ -722,11 +727,13 @@ void general_loop(void *enc_ctx)
|
||||
}
|
||||
|
||||
// Raw caption with FTS file process
|
||||
void rcwt_loop(void *enc_ctx)
|
||||
void rcwt_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
{
|
||||
static unsigned char *parsebuf;
|
||||
static long parsebufsize = 1024;
|
||||
struct cc_subtitle dec_sub;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
|
||||
memset(&dec_sub, 0,sizeof(dec_sub));
|
||||
// As BUFSIZE is a macro this is just a reminder
|
||||
@@ -735,15 +742,15 @@ void rcwt_loop(void *enc_ctx)
|
||||
|
||||
// Generic buffer to hold some data
|
||||
parsebuf = (unsigned char*)malloc(1024);
|
||||
|
||||
|
||||
|
||||
LLONG currfts;
|
||||
uint16_t cbcount = 0;
|
||||
|
||||
int bread = 0; // Bytes read
|
||||
|
||||
buffered_read(parsebuf,11);
|
||||
past+=result;
|
||||
buffered_read(ctx, parsebuf, 11);
|
||||
ctx->past+=result;
|
||||
bread+=(int) result;
|
||||
if (result!=11)
|
||||
{
|
||||
@@ -759,7 +766,7 @@ void rcwt_loop(void *enc_ctx)
|
||||
dbg_print(CCX_DMT_PARSE, "File created by %02X version %02X%02X\nFile format revision: %02X%02X\n",
|
||||
parsebuf[3], parsebuf[4], parsebuf[5],
|
||||
parsebuf[6], parsebuf[7]);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -768,7 +775,7 @@ void rcwt_loop(void *enc_ctx)
|
||||
|
||||
if (parsebuf[6] == 0 && parsebuf[7] == 2)
|
||||
{
|
||||
tlt_read_rcwt();
|
||||
tlt_read_rcwt(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -782,8 +789,8 @@ void rcwt_loop(void *enc_ctx)
|
||||
while(1)
|
||||
{
|
||||
// Read the data header
|
||||
buffered_read(parsebuf,10);
|
||||
past+=result;
|
||||
buffered_read(ctx, parsebuf, 10);
|
||||
ctx->past+=result;
|
||||
bread+=(int) result;
|
||||
|
||||
if (result!=10)
|
||||
@@ -809,8 +816,8 @@ void rcwt_loop(void *enc_ctx)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
parsebufsize = cbcount*3;
|
||||
}
|
||||
buffered_read(parsebuf,cbcount*3);
|
||||
past+=result;
|
||||
buffered_read(ctx, parsebuf, cbcount*3);
|
||||
ctx->past+=result;
|
||||
bread+=(int) result;
|
||||
if (result!=cbcount*3)
|
||||
{
|
||||
@@ -832,7 +839,7 @@ void rcwt_loop(void *enc_ctx)
|
||||
|
||||
for (int j=0; j<cbcount*3; j=j+3)
|
||||
{
|
||||
do_cb(parsebuf+j, &dec_sub);
|
||||
do_cb(dec_ctx, parsebuf+j, &dec_sub);
|
||||
}
|
||||
}
|
||||
if (dec_sub.got_output)
|
||||
125
src/lib_ccx/lib_ccx.c
Normal file
125
src/lib_ccx/lib_ccx.c
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
struct ccx_common_logging_t ccx_common_logging;
|
||||
static struct ccx_decoders_common_settings_t *init_decoder_setting(
|
||||
struct ccx_s_options *opt)
|
||||
{
|
||||
struct ccx_decoders_common_settings_t *setting;
|
||||
|
||||
setting = malloc(sizeof(struct ccx_decoders_common_settings_t));
|
||||
if(!setting)
|
||||
return NULL;
|
||||
|
||||
setting->subs_delay = opt->subs_delay;
|
||||
setting->output_format = opt->write_format;
|
||||
setting->fix_padding = opt->fix_padding;
|
||||
memcpy(&setting->extraction_start,&opt->extraction_start,sizeof(struct ccx_boundary_time));
|
||||
memcpy(&setting->extraction_end,&opt->extraction_end,sizeof(struct ccx_boundary_time));
|
||||
setting->cc_to_stdout = opt->cc_to_stdout;
|
||||
return setting;
|
||||
}
|
||||
static void dinit_decoder_setting (struct ccx_decoders_common_settings_t **setting)
|
||||
{
|
||||
freep(setting);
|
||||
}
|
||||
|
||||
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt)
|
||||
{
|
||||
struct lib_ccx_ctx *ctx;
|
||||
struct ccx_decoder_608_report *report_608;
|
||||
struct ccx_decoders_common_settings_t *dec_setting;
|
||||
|
||||
ctx = malloc(sizeof(struct lib_ccx_ctx));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
memset(ctx,0,sizeof(struct lib_ccx_ctx));
|
||||
|
||||
report_608 = malloc(sizeof(struct ccx_decoder_608_report));
|
||||
if (!report_608)
|
||||
return NULL;
|
||||
memset(report_608,0,sizeof(struct ccx_decoder_608_report));
|
||||
|
||||
ctx->capbufsize = 20000;
|
||||
ctx->capbuf = NULL;
|
||||
ctx->capbuflen = 0; // Bytes read in capbuf
|
||||
|
||||
// Initialize some constants
|
||||
init_ts(ctx);
|
||||
init_avc();
|
||||
|
||||
ctx->stream_mode = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
ctx->auto_stream = opt->auto_stream;
|
||||
ctx->screens_to_process = -1;
|
||||
ctx->current_file = -1;
|
||||
ctx->infd = -1;//Set to -1 to indicate no file is open.
|
||||
// Default name for output files if input is stdin
|
||||
ctx->basefilename_for_stdin=(char *) "stdin";
|
||||
// Default name for output files if input is network
|
||||
ctx->basefilename_for_network=(char *) "network";
|
||||
|
||||
// Set logging functions for libraries
|
||||
ccx_common_logging.debug_ftn = &dbg_print;
|
||||
ccx_common_logging.debug_mask = opt->debug_mask;
|
||||
ccx_common_logging.fatal_ftn = &fatal;
|
||||
ccx_common_logging.log_ftn = &mprint;
|
||||
ccx_common_logging.gui_ftn = &activity_library_process;
|
||||
|
||||
// Need to set the 608 data for the report to the correct variable.
|
||||
ctx->freport.data_from_608 = report_608;
|
||||
// Same applies for 708 data
|
||||
ctx->freport.data_from_708 = &ccx_decoder_708_report;
|
||||
|
||||
// Init shared decoder settings
|
||||
dec_setting = init_decoder_setting(opt);
|
||||
ctx->dec_ctx = init_cc_decode(dec_setting);
|
||||
dinit_decoder_setting(&dec_setting);
|
||||
|
||||
// Init encoder helper variables
|
||||
ccx_encoders_helpers_setup(opt->encoding, opt->nofontcolor, opt->notypesetting, opt->trim_subs);
|
||||
|
||||
// Init 708 decoder(s)
|
||||
ccx_decoders_708_init_library(ctx->basefilename,ctx->extension,opt->print_file_reports);
|
||||
|
||||
// Set output structures for the 608 decoder
|
||||
//ctx->dec_ctx->context_cc608_field_1->out = ctx->dec_ctx->wbout1;
|
||||
//ctx->dec_ctx->context_cc608_field_2->out = ctx->dec_ctx->wbout2;
|
||||
|
||||
// Init XDS buffers
|
||||
ccx_decoders_xds_init_library(&opt->transcript_settings, ctx->subs_delay, opt->millis_separator);
|
||||
//xds_cea608_test();
|
||||
|
||||
//Initialize input files
|
||||
ctx->inputfile = opt->inputfile;
|
||||
ctx->num_input_files = opt->num_input_files;
|
||||
ctx->subs_delay = opt->subs_delay;
|
||||
ctx->wbout1.filename = opt->wbout2.filename;
|
||||
ctx->wbout2.filename = opt->wbout2.filename;
|
||||
ctx->buffer = (unsigned char *) malloc (BUFSIZE);
|
||||
ctx->pesheaderbuf = (unsigned char *) malloc (188); // Never larger anyway
|
||||
|
||||
// Init timing
|
||||
ccx_common_timing_init(&ctx->past,opt->nosync);
|
||||
|
||||
ctx->cc_to_stdout = opt->cc_to_stdout;
|
||||
|
||||
build_parity_table();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void dinit_libraries( struct lib_ccx_ctx **ctx)
|
||||
{
|
||||
struct lib_ccx_ctx *lctx = *ctx;
|
||||
int i = 0;
|
||||
for (i = 0; i < MAX_PID; i++)
|
||||
{
|
||||
if( lctx->PIDs_programs[i])
|
||||
freep(lctx->PIDs_programs + i);
|
||||
}
|
||||
dinit_ts(lctx);
|
||||
dinit_cc_decode(&lctx->dec_ctx);
|
||||
freep(&lctx->buffer);
|
||||
freep(&lctx->pesheaderbuf);
|
||||
freep(&lctx->freport.data_from_608);
|
||||
freep(ctx);
|
||||
}
|
||||
422
src/lib_ccx/lib_ccx.h
Normal file
422
src/lib_ccx/lib_ccx.h
Normal file
@@ -0,0 +1,422 @@
|
||||
#ifndef CCX_CCEXTRACTOR_H
|
||||
#define CCX_CCEXTRACTOR_H
|
||||
|
||||
#define VERSION "0.75"
|
||||
|
||||
// Load common includes and constants for library usage
|
||||
#include "ccx_common_platform.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "ccx_common_common.h"
|
||||
#include "ccx_common_char_encoding.h"
|
||||
#include "ccx_common_structs.h"
|
||||
#include "ccx_common_timing.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
#include "ccx_encoders_common.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#include "ccx_decoders_xds.h"
|
||||
#include "ccx_decoders_708.h"
|
||||
#include "bitstream.h"
|
||||
|
||||
#include "networking.h"
|
||||
|
||||
extern int cc_buffer_saved; // Do we have anything in the CC buffer already?
|
||||
extern int ccblocks_in_avc_total; // Total CC blocks found by the AVC code
|
||||
extern int ccblocks_in_avc_lost; // CC blocks found by the AVC code lost due to overwrites (should be 0)
|
||||
|
||||
#define TS_PMT_MAP_SIZE 128
|
||||
|
||||
struct ts_payload
|
||||
{
|
||||
unsigned char *start; // Payload start
|
||||
unsigned length; // Payload length
|
||||
unsigned pesstart; // PES or PSI start
|
||||
unsigned pid; // Stream PID
|
||||
int counter; // continuity counter
|
||||
int transport_error; // 0 = packet OK, non-zero damaged
|
||||
unsigned char section_buf[1024];
|
||||
int section_index;
|
||||
int section_size;
|
||||
};
|
||||
|
||||
struct PAT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned char *last_pmt_payload;
|
||||
unsigned last_pmt_length;
|
||||
};
|
||||
|
||||
struct PMT_entry
|
||||
{
|
||||
unsigned program_number;
|
||||
unsigned PMT_PID;
|
||||
unsigned elementary_PID;
|
||||
unsigned ccx_stream_type;
|
||||
unsigned printable_stream_type;
|
||||
};
|
||||
|
||||
/* Report information */
|
||||
#define SUB_STREAMS_CNT 10
|
||||
struct file_report
|
||||
{
|
||||
unsigned program_cnt;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned aspect_ratio;
|
||||
unsigned frame_rate;
|
||||
struct ccx_decoder_608_report *data_from_608;
|
||||
struct ccx_decoder_708_report_t *data_from_708;
|
||||
unsigned dvb_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned tlt_sub_pid[SUB_STREAMS_CNT];
|
||||
unsigned mp4_cc_track_cnt;
|
||||
};
|
||||
|
||||
// Stuff for telcc.c
|
||||
struct ccx_s_teletext_config {
|
||||
uint8_t verbose : 1; // should telxcc be verbose?
|
||||
uint16_t page; // teletext page containing cc we want to filter
|
||||
uint16_t tid; // 13-bit packet ID for teletext stream
|
||||
double offset; // time offset in seconds
|
||||
uint8_t bom : 1; // print UTF-8 BOM characters at the beginning of output
|
||||
uint8_t nonempty : 1; // produce at least one (dummy) frame
|
||||
// uint8_t se_mode : 1; // search engine compatible mode => Uses CCExtractor's write_format
|
||||
// uint64_t utc_refvalue; // UTC referential value => Moved to ccx_decoders_common, so can be used for other decoders (608/xds) too
|
||||
uint16_t user_page; // Page selected by user, which MIGHT be different to 'page' depending on autodetection stuff
|
||||
};
|
||||
#define MAX_PID 65536
|
||||
struct lib_ccx_ctx
|
||||
{
|
||||
// TODO relates to fts_global
|
||||
uint32_t global_timestamp;
|
||||
uint32_t min_global_timestamp;
|
||||
int global_timestamp_inited;
|
||||
|
||||
|
||||
// Stuff common to both loops
|
||||
unsigned char *buffer;
|
||||
LLONG past; /* Position in file, if in sync same as ftell() */
|
||||
unsigned char *pesheaderbuf;
|
||||
LLONG inputsize;
|
||||
LLONG total_inputsize;
|
||||
LLONG total_past; // Only in binary concat mode
|
||||
|
||||
int last_reported_progress;
|
||||
|
||||
// Small buffer to help us with the initial sync
|
||||
unsigned char startbytes[STARTBYTESLENGTH];
|
||||
unsigned int startbytes_pos;
|
||||
int startbytes_avail;
|
||||
|
||||
/* Stats */
|
||||
int stat_numuserheaders;
|
||||
int stat_dvdccheaders;
|
||||
int stat_scte20ccheaders;
|
||||
int stat_replay5000headers;
|
||||
int stat_replay4000headers;
|
||||
int stat_dishheaders;
|
||||
int stat_hdtv;
|
||||
int stat_divicom;
|
||||
unsigned total_pulldownfields;
|
||||
unsigned total_pulldownframes;
|
||||
int false_pict_header;
|
||||
|
||||
/* GOP-based timing */
|
||||
int saw_gop_header;
|
||||
int frames_since_last_gop;
|
||||
|
||||
|
||||
/* Time info for timed-transcript */
|
||||
int max_gop_length; // (Maximum) length of a group of pictures
|
||||
int last_gop_length; // Length of the previous group of pictures
|
||||
|
||||
// int hex_mode=HEX_NONE; // Are we processing an hex file?
|
||||
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
enum ccx_stream_mode_enum stream_mode;
|
||||
enum ccx_stream_mode_enum auto_stream;
|
||||
|
||||
|
||||
int rawmode; // Broadcast or DVD
|
||||
// See -d from
|
||||
|
||||
int cc_to_stdout; // If 1, captions go to stdout instead of file
|
||||
|
||||
|
||||
LLONG subs_delay; // ms to delay (or advance) subs
|
||||
|
||||
int startcredits_displayed;
|
||||
int end_credits_displayed;
|
||||
LLONG last_displayed_subs_ms; // When did the last subs end?
|
||||
LLONG screens_to_process; // How many screenfuls we want?
|
||||
char *basefilename; // Input filename without the extension
|
||||
|
||||
const char *extension; // Output extension
|
||||
int current_file; // If current_file!=1, we are processing *inputfile[current_file]
|
||||
|
||||
char **inputfile; // List of files to process
|
||||
int num_input_files; // How many?
|
||||
|
||||
/* Hauppauge support */
|
||||
unsigned hauppauge_warning_shown; // Did we detect a possible Hauppauge capture and told the user already?
|
||||
unsigned teletext_warning_shown; // Did we detect a possible PAL (with teletext subs) and told the user already?
|
||||
|
||||
// Output structures
|
||||
struct ccx_s_write wbout1;
|
||||
struct ccx_s_write wbout2;
|
||||
|
||||
/* File handles */
|
||||
FILE *fh_out_elementarystream;
|
||||
int infd; // descriptor number to input.
|
||||
char *basefilename_for_stdin;
|
||||
char *basefilename_for_network;
|
||||
int PIDs_seen[MAX_PID];
|
||||
struct PMT_entry *PIDs_programs[MAX_PID];
|
||||
struct file_report freport;
|
||||
|
||||
long capbufsize;
|
||||
unsigned char *capbuf;
|
||||
long capbuflen; // Bytes read in capbuf
|
||||
};
|
||||
#ifdef DEBUG_TELEXCC
|
||||
int main_telxcc (int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#define buffered_skip(ctx, bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else result=buffered_read_opt (ctx, NULL,bytes);
|
||||
|
||||
#define buffered_read(ctx, buffer,bytes) if (bytes<=bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer!=NULL) memcpy (buffer,filebuffer+filebuffer_pos,bytes); \
|
||||
filebuffer_pos+=bytes; \
|
||||
result=bytes; \
|
||||
} else { result=buffered_read_opt (ctx, buffer,bytes); if (ccx_options.gui_mode_reports && ccx_options.input_source==CCX_DS_NETWORK) {net_activity_gui++; if (!(net_activity_gui%1000))activity_report_data_read();}}
|
||||
|
||||
#define buffered_read_4(buffer) if (4<=bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { buffer[0]=filebuffer[filebuffer_pos]; \
|
||||
buffer[1]=filebuffer[filebuffer_pos+1]; \
|
||||
buffer[2]=filebuffer[filebuffer_pos+2]; \
|
||||
buffer[3]=filebuffer[filebuffer_pos+3]; \
|
||||
filebuffer_pos+=4; \
|
||||
result=4; } \
|
||||
} else result=buffered_read_opt (buffer,4);
|
||||
|
||||
#define buffered_read_byte(ctx, buffer) if (bytesinbuffer-filebuffer_pos) { \
|
||||
if (buffer) { *buffer=filebuffer[filebuffer_pos]; \
|
||||
filebuffer_pos++; \
|
||||
result=1; } \
|
||||
} else result=buffered_read_opt (ctx, buffer,1);
|
||||
|
||||
LLONG buffered_read_opt (struct lib_ccx_ctx *ctx, unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
struct lib_ccx_ctx* init_libraries(struct ccx_s_options *opt);
|
||||
void dinit_libraries( struct lib_ccx_ctx **ctx);
|
||||
|
||||
//params.c
|
||||
void parse_parameters (struct ccx_s_options *opt, int argc, char *argv[]);
|
||||
void usage (void);
|
||||
int atoi_hex (char *s);
|
||||
int stringztoms (const char *s, struct ccx_boundary_time *bt);
|
||||
|
||||
// general_loop.c
|
||||
void position_sanity_check (void);
|
||||
int init_file_buffer( void );
|
||||
LLONG ps_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
LLONG general_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
void raw_loop (struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
LLONG process_raw (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
|
||||
void general_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
void processhex (char *filename);
|
||||
void rcwt_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
|
||||
// activity.c
|
||||
void activity_header (void);
|
||||
void activity_progress (int percentaje, int cur_min, int cur_sec);
|
||||
void activity_report_version (void);
|
||||
void activity_input_file_closed (void);
|
||||
void activity_input_file_open (const char *filename);
|
||||
void activity_message (const char *fmt, ...);
|
||||
void activity_video_info (int hor_size,int vert_size,
|
||||
const char *aspect_ratio, const char *framerate);
|
||||
void activity_program_number (unsigned program_number);
|
||||
void activity_library_process(enum ccx_common_logging_gui message_type, ...);
|
||||
void activity_report_data_read (void);
|
||||
|
||||
extern LLONG result;
|
||||
extern int end_of_file;
|
||||
extern LLONG inbuf;
|
||||
extern int ccx_bufferdatatype; // Can be RAW or PES
|
||||
|
||||
// asf_functions.c
|
||||
LLONG asf_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// wtv_functions.c
|
||||
LLONG wtv_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// avc_functions.c
|
||||
LLONG process_avc (struct lib_ccx_ctx *ctx, unsigned char *avcbuf, LLONG avcbuflen ,struct cc_subtitle *sub);
|
||||
void init_avc(void);
|
||||
|
||||
// es_functions.c
|
||||
LLONG process_m2v (struct lib_ccx_ctx *ctx, unsigned char *data, LLONG length,struct cc_subtitle *sub);
|
||||
|
||||
extern unsigned top_field_first;
|
||||
|
||||
// es_userdata.c
|
||||
int user_data(struct lib_ccx_ctx *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub);
|
||||
|
||||
// bitstream.c - see bitstream.h
|
||||
|
||||
// file_functions.c
|
||||
LLONG getfilesize (int in);
|
||||
LLONG gettotalfilessize (struct lib_ccx_ctx *ctx);
|
||||
void prepare_for_new_file (struct lib_ccx_ctx *ctx);
|
||||
void close_input_file (struct lib_ccx_ctx *ctx);
|
||||
int switch_to_next_file (struct lib_ccx_ctx *ctx, LLONG bytesinbuffer);
|
||||
void return_to_buffer (unsigned char *buffer, unsigned int bytes);
|
||||
|
||||
// sequencing.c
|
||||
void init_hdcc (void);
|
||||
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number,
|
||||
LLONG current_fts_now,struct cc_subtitle *sub);
|
||||
void anchor_hdcc(int seq);
|
||||
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub);
|
||||
// mp4.c
|
||||
int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx);
|
||||
|
||||
// params_dump.c
|
||||
void params_dump(struct lib_ccx_ctx *ctx);
|
||||
void print_file_report(struct lib_ccx_ctx *ctx);
|
||||
|
||||
// output.c
|
||||
void init_write(struct ccx_s_write *wb, char *filename);
|
||||
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb);
|
||||
void writedata(const unsigned char *data, int length, ccx_decoder_608_context *context, struct cc_subtitle *sub);
|
||||
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile);
|
||||
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data);
|
||||
|
||||
// stream_functions.c
|
||||
void detect_stream_type (struct lib_ccx_ctx *ctx);
|
||||
int detect_myth( struct lib_ccx_ctx *ctx );
|
||||
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen);
|
||||
int read_pts_pes(unsigned char*header, int len);
|
||||
|
||||
// ts_functions.c
|
||||
void init_ts(struct lib_ccx_ctx *ctx);
|
||||
void dinit_ts (struct lib_ccx_ctx *ctx);
|
||||
int ts_readpacket(struct lib_ccx_ctx* ctx);
|
||||
long ts_readstream(struct lib_ccx_ctx *ctx);
|
||||
LLONG ts_getmoredata(struct lib_ccx_ctx *ctx);
|
||||
int write_section(struct lib_ccx_ctx *ctx, struct ts_payload *payload, unsigned char*buf, int size, int pos);
|
||||
int parse_PMT (struct lib_ccx_ctx *ctx, unsigned char *buf, int len, int pos);
|
||||
int parse_PAT (struct lib_ccx_ctx *ctx);
|
||||
|
||||
// myth.c
|
||||
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx);
|
||||
|
||||
// utility.c
|
||||
void fatal(int exit_code, const char *fmt, ...);
|
||||
void dvprint(const char *fmt, ...);
|
||||
void mprint (const char *fmt, ...);
|
||||
void sleep_secs (int secs);
|
||||
void dump (LLONG mask, unsigned char *start, int l, unsigned long abs_start, unsigned clear_high_bit);
|
||||
bool_t in_array(uint16_t *array, uint16_t length, uint16_t element) ;
|
||||
int hex2int (char high, char low);
|
||||
void timestamp_to_srttime(uint64_t timestamp, char *buffer);
|
||||
void timestamp_to_smptetttime(uint64_t timestamp, char *buffer);
|
||||
void millis_to_date (uint64_t timestamp, char *buffer) ;
|
||||
int levenshtein_dist (const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len);
|
||||
#ifndef _WIN32
|
||||
void m_signal(int sig, void (*func)(int));
|
||||
#endif
|
||||
|
||||
|
||||
unsigned encode_line (unsigned char *buffer, unsigned char *text);
|
||||
void buffered_seek (struct lib_ccx_ctx *ctx, int offset);
|
||||
extern void build_parity_table(void);
|
||||
|
||||
void tlt_process_pes_packet(struct lib_ccx_ctx *ctx, uint8_t *buffer, uint16_t size);
|
||||
void telxcc_init(struct lib_ccx_ctx *ctx);
|
||||
void telxcc_close(struct lib_ccx_ctx *ctx);
|
||||
void tlt_read_rcwt(struct lib_ccx_ctx *ctx);
|
||||
|
||||
extern unsigned rollover_bits;
|
||||
extern int global_timestamp_inited;
|
||||
|
||||
extern int strangeheader;
|
||||
|
||||
extern unsigned char *filebuffer;
|
||||
extern LLONG filebuffer_start; // Position of buffer start relative to file
|
||||
extern int filebuffer_pos; // Position of pointer relative to buffer start
|
||||
extern int bytesinbuffer; // Number of bytes we actually have on buffer
|
||||
|
||||
extern const char *desc[256];
|
||||
|
||||
|
||||
extern long FILEBUFFERSIZE; // Uppercase because it used to be a define
|
||||
extern unsigned long net_activity_gui;
|
||||
|
||||
/* General (ES stream) video information */
|
||||
extern unsigned current_hor_size;
|
||||
extern unsigned current_vert_size;
|
||||
extern unsigned current_aspect_ratio;
|
||||
extern unsigned current_frame_rate;
|
||||
|
||||
extern enum ccx_bufferdata_type bufferdatatype; // Can be CCX_BUFFERDATA_TYPE_RAW or CCX_BUFFERDATA_TYPE_PES
|
||||
|
||||
extern int firstcall;
|
||||
|
||||
#define MAXBFRAMES 50
|
||||
#define SORTBUF (2*MAXBFRAMES+1)
|
||||
extern int cc_data_count[SORTBUF];
|
||||
extern unsigned char cc_data_pkts[SORTBUF][10*31*3+1];
|
||||
extern int has_ccdata_buffered;
|
||||
|
||||
extern unsigned char *subline;
|
||||
|
||||
|
||||
// From ts_functions
|
||||
extern unsigned cap_stream_type;
|
||||
extern struct ts_payload payload;
|
||||
extern unsigned char tspacket[188];
|
||||
extern struct PAT_entry pmt_array[TS_PMT_MAP_SIZE];
|
||||
extern uint16_t pmt_array_length;
|
||||
extern unsigned pmtpid;
|
||||
extern unsigned TS_program_number;
|
||||
extern unsigned char *last_pat_payload;
|
||||
extern unsigned last_pat_length;
|
||||
extern long capbuflen;
|
||||
|
||||
|
||||
#define HAUPPAGE_CCPID 1003 // PID for CC's in some Hauppauge recordings
|
||||
|
||||
/* Exit codes. Take this seriously as the GUI depends on them.
|
||||
0 means OK as usual,
|
||||
<100 means display whatever was output to stderr as a warning
|
||||
>=100 means display whatever was output to stdout as an error
|
||||
*/
|
||||
// Some moved to ccx_common_common.h
|
||||
#define EXIT_OK 0
|
||||
#define EXIT_NO_INPUT_FILES 2
|
||||
#define EXIT_TOO_MANY_INPUT_FILES 3
|
||||
#define EXIT_INCOMPATIBLE_PARAMETERS 4
|
||||
#define EXIT_UNABLE_TO_DETERMINE_FILE_SIZE 6
|
||||
#define EXIT_MALFORMED_PARAMETER 7
|
||||
#define EXIT_READ_ERROR 8
|
||||
#define EXIT_NOT_CLASSIFIED 300
|
||||
#define EXIT_ERROR_IN_CAPITALIZATION_FILE 501
|
||||
#define EXIT_BUFFER_FULL 502
|
||||
#define EXIT_MISSING_ASF_HEADER 1001
|
||||
#define EXIT_MISSING_RCWT_HEADER 1002
|
||||
|
||||
extern unsigned teletext_mode;
|
||||
|
||||
#define MAX_TLT_PAGES 1000
|
||||
extern short int seen_sub_page[MAX_TLT_PAGES];
|
||||
|
||||
extern struct ccx_s_teletext_config tlt_config;
|
||||
extern uint32_t tlt_packet_counter;
|
||||
extern uint32_t tlt_frames_produced;
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,8 @@
|
||||
/* This code comes from MythTV.
|
||||
/* This code comes from MythTV.
|
||||
For now, integration with ccextractor is a quick hack. It could get better with time. */
|
||||
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "ccx_decoders_608.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -287,57 +288,57 @@ typedef struct AVPacket
|
||||
|
||||
static AVPacket av;
|
||||
|
||||
int get_be16()
|
||||
int get_be16(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned char a,b;
|
||||
unsigned char *a_p = &a; // Just to suppress warnings
|
||||
unsigned char *b_p = &b;
|
||||
buffered_read_byte (a_p);
|
||||
past++;
|
||||
buffered_read_byte (b_p);
|
||||
past++;
|
||||
buffered_read_byte (ctx, a_p);
|
||||
ctx->past++;
|
||||
buffered_read_byte (ctx, b_p);
|
||||
ctx->past++;
|
||||
return (a<<8) | b;
|
||||
}
|
||||
|
||||
int get_byte ()
|
||||
int get_byte (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned char b;
|
||||
unsigned char *b_p = &b;
|
||||
buffered_read_byte(b_p);
|
||||
buffered_read_byte(ctx, b_p);
|
||||
if (result==1)
|
||||
{
|
||||
past++;
|
||||
ctx->past++;
|
||||
return b;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_be32()
|
||||
unsigned int get_be32(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
unsigned int val;
|
||||
val = get_be16() << 16;
|
||||
val |= get_be16();
|
||||
val = get_be16(ctx) << 16;
|
||||
val |= get_be16(ctx);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static LLONG get_pts(int c)
|
||||
static LLONG get_pts(struct lib_ccx_ctx *ctx, int c)
|
||||
{
|
||||
LLONG pts;
|
||||
int val;
|
||||
|
||||
if (c < 0)
|
||||
c = get_byte();
|
||||
c = get_byte(ctx);
|
||||
pts = (LLONG) ((c >> 1) & 0x07) << 30;
|
||||
val = get_be16();
|
||||
val = get_be16(ctx);
|
||||
pts |= (LLONG) (val >> 1) << 15;
|
||||
val = get_be16();
|
||||
val = get_be16(ctx);
|
||||
pts |= (LLONG) (val >> 1);
|
||||
return pts;
|
||||
}
|
||||
|
||||
static int find_next_start_code(int *size_ptr,
|
||||
static int find_next_start_code(struct lib_ccx_ctx *ctx, int *size_ptr,
|
||||
unsigned int *header_state)
|
||||
{
|
||||
unsigned int state, v;
|
||||
@@ -349,10 +350,10 @@ static int find_next_start_code(int *size_ptr,
|
||||
{
|
||||
unsigned char cx;
|
||||
unsigned char *cx_p = &cx;
|
||||
buffered_read_byte (cx_p);
|
||||
buffered_read_byte (ctx, cx_p);
|
||||
if (result!=1)
|
||||
break;
|
||||
past++;
|
||||
ctx->past++;
|
||||
v = cx;
|
||||
n--;
|
||||
if (state == 0x000001) {
|
||||
@@ -369,45 +370,45 @@ found:
|
||||
return val;
|
||||
}
|
||||
|
||||
void url_fskip (int length)
|
||||
void url_fskip (struct lib_ccx_ctx *ctx, int length)
|
||||
{
|
||||
buffered_seek (length);
|
||||
past+=length;
|
||||
buffered_seek (ctx, length);
|
||||
ctx->past+=length;
|
||||
}
|
||||
|
||||
static long mpegps_psm_parse(void)
|
||||
static long mpegps_psm_parse(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
int psm_length, ps_info_length, es_map_length;
|
||||
|
||||
psm_length = get_be16();
|
||||
get_byte();
|
||||
get_byte();
|
||||
ps_info_length = get_be16();
|
||||
psm_length = get_be16(ctx);
|
||||
get_byte(ctx);
|
||||
get_byte(ctx);
|
||||
ps_info_length = get_be16(ctx);
|
||||
|
||||
/* skip program_stream_info */
|
||||
url_fskip(ps_info_length);
|
||||
es_map_length = get_be16();
|
||||
url_fskip(ctx, ps_info_length);
|
||||
es_map_length = get_be16(ctx);
|
||||
|
||||
/* at least one es available? */
|
||||
while (es_map_length >= 4)
|
||||
{
|
||||
unsigned char type = (unsigned char) get_byte();
|
||||
unsigned char es_id =(unsigned char) get_byte();
|
||||
unsigned int es_info_length = get_be16();
|
||||
unsigned char type = (unsigned char) get_byte(ctx);
|
||||
unsigned char es_id =(unsigned char) get_byte(ctx);
|
||||
unsigned int es_info_length = get_be16(ctx);
|
||||
/* remember mapping from stream id to stream type */
|
||||
psm_es_type[es_id] = type;
|
||||
/* skip program_stream_info */
|
||||
url_fskip(es_info_length);
|
||||
url_fskip(ctx, es_info_length);
|
||||
es_map_length -= 4 + es_info_length;
|
||||
}
|
||||
get_be32(); /* crc32 */
|
||||
get_be32(ctx); /* crc32 */
|
||||
return 2 + psm_length;
|
||||
}
|
||||
|
||||
|
||||
static int mpegps_read_pes_header(int *pstart_code,
|
||||
static int mpegps_read_pes_header(struct lib_ccx_ctx *ctx, int *pstart_code,
|
||||
LLONG *ppts, LLONG *pdts)
|
||||
{
|
||||
{
|
||||
int len, size, startcode, c, flags, header_len;
|
||||
LLONG pts, dts;
|
||||
|
||||
@@ -415,7 +416,7 @@ redo:
|
||||
/* next start code (should be immediately after) */
|
||||
header_state = 0xff;
|
||||
size = MAX_SYNC_SIZE;
|
||||
startcode = find_next_start_code(&size, &header_state);
|
||||
startcode = find_next_start_code(ctx, &size, &header_state);
|
||||
//printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
|
||||
if (startcode < 0)
|
||||
return AVERROR_IO;
|
||||
@@ -427,14 +428,14 @@ redo:
|
||||
startcode == PRIVATE_STREAM_2)
|
||||
{
|
||||
/* skip them */
|
||||
len = get_be16();
|
||||
// url_fskip(len);
|
||||
len = get_be16(ctx);
|
||||
// url_fskip(ctx, len);
|
||||
goto redo;
|
||||
}
|
||||
position_sanity_check();
|
||||
if (startcode == PROGRAM_STREAM_MAP)
|
||||
{
|
||||
mpegps_psm_parse();
|
||||
mpegps_psm_parse(ctx);
|
||||
goto redo;
|
||||
}
|
||||
|
||||
@@ -444,7 +445,7 @@ redo:
|
||||
(startcode == 0x1bd)))
|
||||
goto redo;
|
||||
|
||||
len = get_be16();
|
||||
len = get_be16(ctx);
|
||||
pts = AV_NOPTS_VALUE;
|
||||
dts = AV_NOPTS_VALUE;
|
||||
position_sanity_check();
|
||||
@@ -452,7 +453,7 @@ redo:
|
||||
for(;;) {
|
||||
if (len < 1)
|
||||
goto redo;
|
||||
c = get_byte();
|
||||
c = get_byte(ctx);
|
||||
len--;
|
||||
/* XXX: for mpeg1, should test only bit 7 */
|
||||
if (c != 0xff)
|
||||
@@ -463,21 +464,21 @@ redo:
|
||||
/* buffer scale & size */
|
||||
if (len < 2)
|
||||
goto redo;
|
||||
get_byte();
|
||||
c = get_byte();
|
||||
get_byte(ctx);
|
||||
c = get_byte(ctx);
|
||||
len -= 2;
|
||||
}
|
||||
position_sanity_check();
|
||||
if ((c & 0xf0) == 0x20) {
|
||||
if (len < 4)
|
||||
goto redo;
|
||||
dts = pts = get_pts( c);
|
||||
dts = pts = get_pts(ctx, c);
|
||||
len -= 4;
|
||||
} else if ((c & 0xf0) == 0x30) {
|
||||
if (len < 9)
|
||||
goto redo;
|
||||
pts = get_pts(c);
|
||||
dts = get_pts(-1);
|
||||
pts = get_pts(ctx, c);
|
||||
dts = get_pts(ctx, -1);
|
||||
len -= 9;
|
||||
} else if ((c & 0xc0) == 0x80) {
|
||||
/* mpeg 2 PES */
|
||||
@@ -487,20 +488,20 @@ redo:
|
||||
goto redo;
|
||||
}
|
||||
#endif
|
||||
flags = get_byte();
|
||||
header_len = get_byte();
|
||||
flags = get_byte(ctx);
|
||||
header_len = get_byte(ctx);
|
||||
len -= 2;
|
||||
if (header_len > len)
|
||||
goto redo;
|
||||
if ((flags & 0xc0) == 0x80) {
|
||||
dts = pts = get_pts(-1);
|
||||
dts = pts = get_pts(ctx, -1);
|
||||
if (header_len < 5)
|
||||
goto redo;
|
||||
header_len -= 5;
|
||||
len -= 5;
|
||||
} if ((flags & 0xc0) == 0xc0) {
|
||||
pts = get_pts( -1);
|
||||
dts = get_pts( -1);
|
||||
pts = get_pts(ctx, -1);
|
||||
dts = get_pts(ctx, -1);
|
||||
if (header_len < 10)
|
||||
goto redo;
|
||||
header_len -= 10;
|
||||
@@ -508,7 +509,7 @@ redo:
|
||||
}
|
||||
len -= header_len;
|
||||
while (header_len > 0) {
|
||||
get_byte();
|
||||
get_byte(ctx);
|
||||
header_len--;
|
||||
}
|
||||
}
|
||||
@@ -519,15 +520,15 @@ redo:
|
||||
{
|
||||
if (len < 1)
|
||||
goto redo;
|
||||
startcode = get_byte();
|
||||
startcode = get_byte(ctx);
|
||||
len--;
|
||||
if (startcode >= 0x80 && startcode <= 0xbf) {
|
||||
/* audio: skip header */
|
||||
if (len < 3)
|
||||
goto redo;
|
||||
get_byte();
|
||||
get_byte();
|
||||
get_byte();
|
||||
get_byte(ctx);
|
||||
get_byte(ctx);
|
||||
get_byte(ctx);
|
||||
len -= 3;
|
||||
}
|
||||
}
|
||||
@@ -550,9 +551,10 @@ static int cc608_good_parity(const int *parity_table, unsigned int data)
|
||||
}
|
||||
|
||||
|
||||
void ProcessVBIDataPacket(struct cc_subtitle *sub)
|
||||
{
|
||||
void ProcessVBIDataPacket(struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
const unsigned char *meat = av.data;
|
||||
if (meat==NULL)
|
||||
{
|
||||
@@ -561,6 +563,7 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
|
||||
}
|
||||
|
||||
LLONG linemask = 0;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
// unsigned long long utc = lastccptsu;
|
||||
|
||||
// [i]tv0 means there is a linemask
|
||||
@@ -614,7 +617,7 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
|
||||
ccdata[0]=0x04; // Field 1
|
||||
ccdata[1]=meat[1];
|
||||
ccdata[2]=meat[2];
|
||||
do_cb(ccdata,sub);
|
||||
do_cb(dec_ctx, ccdata, sub);
|
||||
// processed_ccblocks++; // Not sure this is accurate
|
||||
}
|
||||
else
|
||||
@@ -622,7 +625,7 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
|
||||
ccdata[0]=0x05; // Field 1
|
||||
ccdata[1]=meat[1];
|
||||
ccdata[2]=meat[2];
|
||||
do_cb(ccdata, sub);
|
||||
do_cb(dec_ctx, ccdata, sub);
|
||||
}
|
||||
}
|
||||
// utc += 33367;
|
||||
@@ -643,13 +646,13 @@ void ProcessVBIDataPacket(struct cc_subtitle *sub)
|
||||
// lastccptsu = utc;
|
||||
}
|
||||
|
||||
static int mpegps_read_packet(void)
|
||||
static int mpegps_read_packet(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
LLONG pts, dts;
|
||||
|
||||
int len, startcode, type, codec_id = 0, es_type;
|
||||
redo:
|
||||
len = mpegps_read_pes_header(&startcode, &pts, &dts);
|
||||
len = mpegps_read_pes_header(ctx, &startcode, &pts, &dts);
|
||||
if (len < 0)
|
||||
return len;
|
||||
position_sanity_check();
|
||||
@@ -694,11 +697,11 @@ redo:
|
||||
{
|
||||
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
|
||||
unsigned char buf[8];
|
||||
buffered_read (buf,8);
|
||||
past+=8;
|
||||
buffered_read (ctx, buf,8);
|
||||
ctx->past+=8;
|
||||
// get_buffer(&s->pb, buf, 8);
|
||||
buffered_seek (-8);
|
||||
past-=8;
|
||||
buffered_seek(ctx, -8);
|
||||
ctx->past-=8;
|
||||
if(!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1))
|
||||
codec_id = CODEC_ID_CAVS;
|
||||
else
|
||||
@@ -725,7 +728,7 @@ redo:
|
||||
} else {
|
||||
skip:
|
||||
// skip packet
|
||||
url_fskip(len);
|
||||
url_fskip(ctx, len);
|
||||
goto redo;
|
||||
}
|
||||
// no stream found: add a new stream
|
||||
@@ -752,9 +755,9 @@ goto skip; */
|
||||
// audio data
|
||||
if (len <= 3)
|
||||
goto skip;
|
||||
get_byte(); // emphasis (1), muse(1), reserved(1), frame number(5)
|
||||
get_byte(); // quant (2), freq(2), reserved(1), channels(3)
|
||||
get_byte(); // dynamic range control (0x80 = off)
|
||||
get_byte(ctx); // emphasis (1), muse(1), reserved(1), frame number(5)
|
||||
get_byte(ctx); // quant (2), freq(2), reserved(1), channels(3)
|
||||
get_byte(ctx); // dynamic range control (0x80 = off)
|
||||
len -= 3;
|
||||
//freq = (b1 >> 4) & 3;
|
||||
//st->codec->sample_rate = lpcm_freq_tab[freq];
|
||||
@@ -776,8 +779,8 @@ goto skip; */
|
||||
}
|
||||
av.codec_id=codec_id;
|
||||
av.type=type;
|
||||
buffered_read (av.data,av.size);
|
||||
past+=av.size;
|
||||
buffered_read (ctx, av.data,av.size);
|
||||
ctx->past+=av.size;
|
||||
position_sanity_check();
|
||||
// LSEEK (fh,pkt->size,SEEK_CUR);
|
||||
av.pts = pts;
|
||||
@@ -823,15 +826,17 @@ void build_parity_table (void)
|
||||
cc608_build_parity_table(cc608_parity_table);
|
||||
}
|
||||
|
||||
void myth_loop(void *enc_ctx)
|
||||
{
|
||||
void myth_loop(struct lib_ccx_ctx *ctx, void *enc_ctx)
|
||||
{
|
||||
int rc;
|
||||
int has_vbi=0;
|
||||
int has_vbi=0;
|
||||
LLONG saved = 0;
|
||||
struct cc_subtitle dec_sub;
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
|
||||
av.data=NULL;
|
||||
ccx_options.buffer_input = 1;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
if (init_file_buffer())
|
||||
{
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
|
||||
@@ -843,7 +848,7 @@ void myth_loop(void *enc_ctx)
|
||||
saved=0;
|
||||
|
||||
memset(&dec_sub, 0, sizeof(dec_sub));
|
||||
while (!processed_enough && (rc=mpegps_read_packet ())==0)
|
||||
while (!dec_ctx->processed_enough && (rc=mpegps_read_packet(ctx))==0)
|
||||
{
|
||||
position_sanity_check();
|
||||
if (av.codec_id==CODEC_ID_MPEG2VBI && av.type==CODEC_TYPE_DATA)
|
||||
@@ -852,9 +857,9 @@ void myth_loop(void *enc_ctx)
|
||||
{
|
||||
mprint ("\rDetected VBI data, disabling user-data packet analysis (not needed).\n");
|
||||
has_vbi=1;
|
||||
}
|
||||
}
|
||||
//fts_now=LLONG((processed_ccblocks*1000)/29.97);
|
||||
ProcessVBIDataPacket(&dec_sub);
|
||||
ProcessVBIDataPacket(ctx, &dec_sub);
|
||||
}
|
||||
/* This needs a lot more testing */
|
||||
if (av.codec_id==CODEC_ID_MPEG2VIDEO && av.type==CODEC_TYPE_VIDEO )
|
||||
@@ -865,7 +870,7 @@ void myth_loop(void *enc_ctx)
|
||||
desp_length=length*2; // *2, just to reduce possible future reallocs
|
||||
desp=(unsigned char *) realloc (desp,desp_length); // 16, some extra
|
||||
if (!desp)
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
|
||||
fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory.\n");
|
||||
}
|
||||
if (av.pts!=AV_NOPTS_VALUE)
|
||||
{
|
||||
@@ -874,33 +879,33 @@ void myth_loop(void *enc_ctx)
|
||||
pts_set=1;
|
||||
}
|
||||
memcpy (desp+saved,av.data,av.size);
|
||||
LLONG used = process_m2v(desp, length, &dec_sub);
|
||||
LLONG used = process_m2v(ctx, desp, length, &dec_sub);
|
||||
memmove (desp,desp+used,(unsigned int) (length-used));
|
||||
saved=length-used;
|
||||
}
|
||||
}
|
||||
|
||||
if (ccx_options.live_stream)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
int th=cur_sec/10;
|
||||
if (last_reported_progress!=th)
|
||||
if (ctx->last_reported_progress!=th)
|
||||
{
|
||||
activity_progress (-1, cur_sec/60, cur_sec%60);
|
||||
last_reported_progress = th;
|
||||
ctx->last_reported_progress = th;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (total_inputsize > 0 )
|
||||
if (ctx->total_inputsize > 0 )
|
||||
{
|
||||
int progress = (int) ((((total_past+past)>>8)*100)/(total_inputsize>>8));
|
||||
if (last_reported_progress != progress)
|
||||
int progress = (int) ((((ctx->total_past+ctx->past)>>8)*100)/(ctx->total_inputsize>>8));
|
||||
if (ctx->last_reported_progress != progress)
|
||||
{
|
||||
int cur_sec = (int) (get_fts() / 1000);
|
||||
activity_progress (progress, cur_sec/60, cur_sec%60);
|
||||
|
||||
fflush (stdout);
|
||||
last_reported_progress = progress;
|
||||
ctx->last_reported_progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "networking.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -124,7 +124,7 @@ void net_send_header(const unsigned char *data, size_t len)
|
||||
|
||||
if (ERROR == ok)
|
||||
{
|
||||
printf("Internal server error\n");
|
||||
printf("Internal server error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ int ask_passwd(int sd)
|
||||
{
|
||||
mprint("Too many connections to the server, try later\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (ERROR == ok)
|
||||
{
|
||||
mprint("Internal server error\n");
|
||||
@@ -581,7 +581,7 @@ int tcp_bind(const char *port, int *family)
|
||||
if (bind(sockfd, p->ai_addr, p->ai_addrlen) < 0)
|
||||
{
|
||||
#if _WIN32
|
||||
wprintf(L"bind() eror: %ld\n", WSAGetLastError());
|
||||
wprintf(L"bind() error: %ld\n", WSAGetLastError());
|
||||
closesocket(sockfd);
|
||||
#else
|
||||
mprint("bind() error: %s\n", strerror(errno));
|
||||
329
src/lib_ccx/ocr.c
Normal file
329
src/lib_ccx/ocr.c
Normal file
@@ -0,0 +1,329 @@
|
||||
#include "png.h"
|
||||
#include "lib_ccx.h"
|
||||
#ifdef ENABLE_OCR
|
||||
#include "platform.h"
|
||||
#include "capi.h"
|
||||
#include "ccx_common_constants.h"
|
||||
#include "allheaders.h"
|
||||
#include <dirent.h>
|
||||
#include "spupng_encoder.h"
|
||||
|
||||
struct ocrCtx
|
||||
{
|
||||
TessBaseAPI* api;
|
||||
};
|
||||
|
||||
struct transIntensity
|
||||
{
|
||||
uint8_t *t;
|
||||
png_color *palette;
|
||||
};
|
||||
static int check_trans_tn_intensity(const void *p1, const void *p2, void *arg)
|
||||
{
|
||||
struct transIntensity *ti = arg;
|
||||
unsigned char* tmp = (unsigned char*)p1;
|
||||
unsigned char* act = (unsigned char*)p2;
|
||||
unsigned char tmp_i;
|
||||
unsigned char act_i;
|
||||
/** TODO verify that RGB follow ITU-R BT.709
|
||||
* Below fomula is valid only for 709 standurd
|
||||
* Y = 0.2126 R + 0.7152 G + 0.0722 B
|
||||
*/
|
||||
tmp_i = (0.2126 * ti->palette[*tmp].red) + (0.7152 * ti->palette[*tmp].green) + (0.0722 * ti->palette[*tmp].blue);
|
||||
act_i = (0.2126 * ti->palette[*act].red) + (0.7152 * ti->palette[*act].green) + (0.0722 * ti->palette[*act].blue);;
|
||||
|
||||
if (ti->t[*tmp] < ti->t[*act] || (ti->t[*tmp] == ti->t[*act] && tmp_i < act_i))
|
||||
return -1;
|
||||
else if (ti->t[*tmp] == ti->t[*act] && tmp_i == act_i)
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int search_language_pack(const char *dirname,const char *lang)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *dirp;
|
||||
char filename[256];
|
||||
if ((dp = opendir(dirname)) == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
snprintf(filename, 256, "%s.traineddata",lang);
|
||||
while ((dirp = readdir(dp)) != NULL)
|
||||
{
|
||||
if(!strcmp(dirp->d_name, filename))
|
||||
{
|
||||
closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void delete_ocr (struct ocrCtx* ctx)
|
||||
{
|
||||
TessBaseAPIEnd(ctx->api);
|
||||
TessBaseAPIDelete(ctx->api);
|
||||
freep(&ctx);
|
||||
}
|
||||
void* init_ocr(int lang_index)
|
||||
{
|
||||
int ret;
|
||||
struct ocrCtx* ctx;
|
||||
|
||||
ctx = (struct ocrCtx*)malloc(sizeof(struct ocrCtx));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
ctx->api = TessBaseAPICreate();
|
||||
|
||||
/* if language was undefined use english */
|
||||
if(lang_index == 0)
|
||||
{
|
||||
/* select english */
|
||||
lang_index = 1;
|
||||
}
|
||||
|
||||
/* if langauge pack not found use english */
|
||||
ret = search_language_pack("tessdata",language[lang_index]);
|
||||
if(ret < 0 )
|
||||
{
|
||||
/* select english */
|
||||
lang_index = 1;
|
||||
}
|
||||
ret = TessBaseAPIInit3(ctx->api,"", language[lang_index]);
|
||||
if(ret < 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
return ctx;
|
||||
fail:
|
||||
delete_ocr(ctx);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h)
|
||||
{
|
||||
PIX *pix;
|
||||
char*text_out= NULL;
|
||||
int i,j,index;
|
||||
unsigned int wpl;
|
||||
unsigned int *data,*ppixel;
|
||||
struct ocrCtx* ctx = arg;
|
||||
pix = pixCreate(w, h, 32);
|
||||
if(pix == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
wpl = pixGetWpl(pix);
|
||||
data = pixGetData(pix);
|
||||
#if LEPTONICA_VERSION > 69
|
||||
pixSetSpp(pix, 4);
|
||||
#endif
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
ppixel = data + i * wpl;
|
||||
for (j = 0; j < w; j++)
|
||||
{
|
||||
index = indata[i * w + (j)];
|
||||
composeRGBPixel(palette[index].red, palette[index].green,palette[index].blue, ppixel);
|
||||
SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL,alpha[index]);
|
||||
ppixel++;
|
||||
}
|
||||
}
|
||||
|
||||
text_out = TessBaseAPIProcessPage(ctx->api, pix, 0, NULL, NULL, 0);
|
||||
if(!text_out)
|
||||
printf("\nsomething messy\n");
|
||||
|
||||
//TessDeleteText(text_out);
|
||||
pixDestroy(&pix);
|
||||
|
||||
return text_out;
|
||||
}
|
||||
/*
|
||||
* @param alpha out
|
||||
* @param intensity in
|
||||
* @param palette out should be already initialized
|
||||
* @param bitmap in
|
||||
* @param size in size of bitmap
|
||||
* @param max_color in
|
||||
* @param nb_color in
|
||||
*/
|
||||
static int quantize_map(png_byte *alpha, png_color *palette,
|
||||
uint8_t *bitmap, int size, int max_color, int nb_color)
|
||||
{
|
||||
/*
|
||||
* occurrence of color in image
|
||||
*/
|
||||
uint32_t *histogram = NULL;
|
||||
/* intensity ordered table */
|
||||
uint8_t *iot = NULL;
|
||||
/* array of color with most occurrence according to histogram
|
||||
* save index of intensity order table
|
||||
*/
|
||||
uint32_t *mcit = NULL;
|
||||
struct transIntensity ti = { alpha,palette};
|
||||
|
||||
int ret = 0;
|
||||
|
||||
histogram = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!histogram)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
iot = (uint8_t*) malloc(nb_color * sizeof(uint8_t));
|
||||
if (!iot)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mcit = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!mcit)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(histogram, 0, nb_color * sizeof(uint32_t));
|
||||
|
||||
/* initializing intensity ordered table with serial order of unsorted color table */
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
iot[i] = i;
|
||||
}
|
||||
memset(mcit, 0, nb_color * sizeof(uint32_t));
|
||||
|
||||
/* calculate histogram of image */
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
histogram[bitmap[i]]++;
|
||||
}
|
||||
/* sorted in increasing order of intensity */
|
||||
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
|
||||
|
||||
#if OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("Intensity ordered table\n");
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
ccx_common_logging.log_ftn("%02d) map %02d hist %02d\n",
|
||||
i, iot[i], histogram[iot[i]]);
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* using selection sort since need to find only max_color
|
||||
* Hostogram becomes invalid in this loop
|
||||
*/
|
||||
for (int i = 0; i < max_color; i++)
|
||||
{
|
||||
uint32_t max_val = 0;
|
||||
uint32_t max_ind = 0;
|
||||
int j;
|
||||
for (j = 0; j < nb_color; j++)
|
||||
{
|
||||
if (max_val < histogram[iot[j]])
|
||||
{
|
||||
max_val = histogram[iot[j]];
|
||||
max_ind = j;
|
||||
}
|
||||
}
|
||||
for (j = i; j > 0 && max_ind < mcit[j - 1]; j--)
|
||||
{
|
||||
mcit[j] = mcit[j - 1];
|
||||
}
|
||||
mcit[j] = max_ind;
|
||||
histogram[iot[max_ind]] = 0;
|
||||
}
|
||||
|
||||
#if OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("max redundant intensities table\n");
|
||||
for (int i = 0; i < max_color; i++)
|
||||
{
|
||||
ccx_common_logging.log_ftn("%02d) mcit %02d\n",
|
||||
i, mcit[i]);
|
||||
}
|
||||
#endif
|
||||
for (int i = 0, mxi = 0; i < nb_color; i++)
|
||||
{
|
||||
int step, inc;
|
||||
if (i == mcit[mxi])
|
||||
{
|
||||
mxi = (mxi < max_color) ? mxi + 1 : mxi;
|
||||
continue;
|
||||
}
|
||||
inc = (mxi) ? -1 : 0;
|
||||
step = mcit[mxi + inc] + ((mcit[mxi] - mcit[mxi + inc]) / 2);
|
||||
if (i <= step)
|
||||
{
|
||||
int index = iot[mcit[mxi + inc]];
|
||||
alpha[iot[i]] = alpha[index];
|
||||
palette[iot[i]].red = palette[index].red;
|
||||
palette[iot[i]].blue = palette[index].blue;
|
||||
palette[iot[i]].green = palette[index].green;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = iot[mcit[mxi]];
|
||||
alpha[iot[i]] = alpha[index];
|
||||
palette[iot[i]].red = palette[index].red;
|
||||
palette[iot[i]].blue = palette[index].blue;
|
||||
palette[iot[i]].green = palette[index].green;
|
||||
}
|
||||
|
||||
}
|
||||
#if OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("Colors present in quantized Image\n");
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
ccx_common_logging.log_ftn("%02d)r %03d g %03d b %03d a %03d\n",
|
||||
i, palette[i].red, palette[i].green, palette[i].blue, alpha[i]);
|
||||
}
|
||||
#endif
|
||||
end: freep(&histogram);
|
||||
freep(&mcit);
|
||||
freep(&iot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ocr_rect(void* arg, struct cc_bitmap *rect, char **str)
|
||||
{
|
||||
int ret = 0;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
|
||||
palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
|
||||
if(!palette)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
|
||||
if(!alpha)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* TODO do rectangle wise, one color table should not be used for all rectangles */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect->data[1],rect->nb_colors);
|
||||
|
||||
quantize_map(alpha, palette, rect->data[0], rect->w * rect->h, 3, rect->nb_colors);
|
||||
*str = ocr_bitmap(arg, palette, alpha, rect->data[0], rect->w, rect->h);
|
||||
end:
|
||||
freep(&palette);
|
||||
freep(&alpha);
|
||||
return ret;
|
||||
|
||||
}
|
||||
#else
|
||||
char* ocr_bitmap(png_color *palette,png_byte *alpha, unsigned char* indata,unsigned char d,int w, int h)
|
||||
{
|
||||
mprint("ocr not supported without tesseract\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
9
src/lib_ccx/ocr.h
Normal file
9
src/lib_ccx/ocr.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef OCR_H
|
||||
#define OCR_H
|
||||
#include <png.h>
|
||||
|
||||
void* init_ocr(int lang_index);
|
||||
char* ocr_bitmap(void* arg, png_color *palette,png_byte *alpha, unsigned char* indata,int w, int h);
|
||||
int ocr_rect(void* arg, struct cc_bitmap *rect, char **str);
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,20 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* TODO remove dependency of encoder by removing writeDVDraw from this file */
|
||||
#include "ccx_encoders_structs.h"
|
||||
|
||||
void init_write (struct ccx_s_write *wb)
|
||||
void init_write (struct ccx_s_write *wb,char *filename)
|
||||
{
|
||||
memset(wb, 0, sizeof(struct ccx_s_write));
|
||||
wb->fh=-1;
|
||||
wb->filename=NULL;
|
||||
}
|
||||
wb->filename=filename;
|
||||
}
|
||||
|
||||
void writeraw (const unsigned char *data, int length, struct ccx_s_write *wb)
|
||||
{
|
||||
@@ -29,7 +32,7 @@ void writedata(const unsigned char *data, int length, ccx_decoder_608_context *c
|
||||
if (context && context->out)
|
||||
writeraw (data,length,context->out);
|
||||
}
|
||||
else if (ccx_options.write_format==CCX_OF_SMPTETT ||
|
||||
else if (ccx_options.write_format==CCX_OF_SMPTETT ||
|
||||
ccx_options.write_format==CCX_OF_SAMI ||
|
||||
ccx_options.write_format==CCX_OF_SRT ||
|
||||
ccx_options.write_format==CCX_OF_TRANSCRIPT ||
|
||||
@@ -40,10 +43,10 @@ void writedata(const unsigned char *data, int length, ccx_decoder_608_context *c
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "Should not be reached!");
|
||||
}
|
||||
|
||||
void flushbuffer (struct ccx_s_write *wb, int closefile)
|
||||
void flushbuffer (struct lib_ccx_ctx *ctx, struct ccx_s_write *wb, int closefile)
|
||||
{
|
||||
if (closefile && wb!=NULL && wb->fh!=-1 && !cc_to_stdout)
|
||||
close (wb->fh);
|
||||
if (closefile && wb!=NULL && wb->fh!=-1 && !ctx->cc_to_stdout)
|
||||
close (wb->fh);
|
||||
}
|
||||
|
||||
void writeDVDraw (const unsigned char *data1, int length1,
|
||||
@@ -51,7 +54,7 @@ void writeDVDraw (const unsigned char *data1, int length1,
|
||||
struct ccx_s_write *wb)
|
||||
{
|
||||
/* these are only used by DVD raw mode: */
|
||||
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
|
||||
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
|
||||
loop 3: 11 elements, rest: 15 elements */
|
||||
static int datacount = 0; /* counts within loop */
|
||||
|
||||
@@ -65,26 +68,26 @@ void writeDVDraw (const unsigned char *data1, int length1,
|
||||
if (loopcount==3)
|
||||
{
|
||||
write (wb->fh,lc3,sizeof (lc3));
|
||||
if (data2 && length2)
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
}
|
||||
if (loopcount>3)
|
||||
{
|
||||
write (wb->fh,lc4,sizeof (lc4));
|
||||
if (data2 && length2)
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
}
|
||||
}
|
||||
datacount++;
|
||||
write (wb->fh,lc5,sizeof (lc5));
|
||||
if (data1 && length1)
|
||||
if (data1 && length1)
|
||||
write (wb->fh,data1,length1);
|
||||
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
|
||||
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
|
||||
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) &&
|
||||
(datacount < 8)) || (( loopcount == 3) && (datacount < 11)) ||
|
||||
((loopcount > 3) && (datacount < 15)))
|
||||
{
|
||||
write (wb->fh,lc6,sizeof (lc6));
|
||||
if (data2 && length2)
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
}
|
||||
else
|
||||
@@ -92,46 +95,50 @@ void writeDVDraw (const unsigned char *data1, int length1,
|
||||
if (loopcount==1)
|
||||
{
|
||||
write (wb->fh,lc6,sizeof (lc6));
|
||||
if (data2 && length2)
|
||||
if (data2 && length2)
|
||||
write (wb->fh,data2,length2);
|
||||
}
|
||||
loopcount++;
|
||||
datacount=0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void printdata (const unsigned char *data1, int length1,
|
||||
void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int length1,
|
||||
const unsigned char *data2, int length2, struct cc_subtitle *sub)
|
||||
{
|
||||
if (ccx_options.write_format==CCX_OF_DVDRAW)
|
||||
writeDVDraw (data1,length1,data2,length2,&wbout1);
|
||||
struct ccx_decoder_608_context *field_1 = ctx->context_cc608_field_1;
|
||||
struct ccx_decoder_608_context *field_2 = ctx->context_cc608_field_2;
|
||||
struct ccx_s_write *wbout1 = ctx->wbout1;
|
||||
if (ctx->write_format==CCX_OF_DVDRAW)
|
||||
writeDVDraw (data1, length1, data2, length2, wbout1);
|
||||
else /* Broadcast raw or any non-raw */
|
||||
{
|
||||
if (length1 && ccx_options.extract!=2)
|
||||
{
|
||||
writedata(data1, length1, &context_cc608_field_1, sub);
|
||||
}
|
||||
if (length2)
|
||||
{
|
||||
if (length1 && ccx_options.extract != 2)
|
||||
{
|
||||
if (ccx_options.extract!=1)
|
||||
writedata(data2, length2, &context_cc608_field_2, sub);
|
||||
writedata(data1, length1, field_1, sub);
|
||||
}
|
||||
if (length2)
|
||||
{
|
||||
if (ccx_options.extract != 1)
|
||||
writedata(data2, length2, field_2, sub);
|
||||
else // User doesn't want field 2 data, but we want XDS.
|
||||
writedata (data2,length2,NULL, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Buffer data with the same FTS and write when a new FTS or data==NULL
|
||||
* is encountered */
|
||||
void writercwtdata (const unsigned char *data)
|
||||
void writercwtdata (struct lib_cc_decode *ctx, const unsigned char *data)
|
||||
{
|
||||
static LLONG prevfts = -1;
|
||||
LLONG currfts = fts_now + fts_global;
|
||||
static uint16_t cbcount = 0;
|
||||
static int cbempty=0;
|
||||
static unsigned char cbbuffer[0xFFFF*3]; // TODO: use malloc
|
||||
static unsigned char cbheader[8+2];
|
||||
static LLONG prevfts = -1;
|
||||
LLONG currfts = fts_now + fts_global;
|
||||
static uint16_t cbcount = 0;
|
||||
static int cbempty=0;
|
||||
static unsigned char cbbuffer[0xFFFF*3]; // TODO: use malloc
|
||||
static unsigned char cbheader[8+2];
|
||||
struct ccx_s_write *wbout1 = ctx->wbout1;
|
||||
|
||||
if ( (prevfts != currfts && prevfts != -1)
|
||||
|| data == NULL
|
||||
@@ -178,14 +185,16 @@ void writercwtdata (const unsigned char *data)
|
||||
|
||||
if (cbcount > 0)
|
||||
{
|
||||
writeraw(cbheader,10,&wbout1);
|
||||
writeraw(cbbuffer,3*cbcount, &wbout1);
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
{
|
||||
net_send_cc(cbheader, 10);
|
||||
net_send_cc(cbbuffer, 3*cbcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeraw(cbheader,10,wbout1);
|
||||
writeraw(cbbuffer,3*cbcount, wbout1);
|
||||
}
|
||||
}
|
||||
cbcount = 0;
|
||||
cbempty = 0;
|
||||
@@ -193,7 +202,7 @@ void writercwtdata (const unsigned char *data)
|
||||
|
||||
if ( data )
|
||||
{
|
||||
// Store the data while the FTS is unchanged
|
||||
// Store the data while the FTS is unchanged
|
||||
|
||||
unsigned char cc_valid = (*data & 4) >> 2;
|
||||
unsigned char cc_type = *data & 3;
|
||||
@@ -228,14 +237,16 @@ void writercwtdata (const unsigned char *data)
|
||||
memcpy(cbbuffer, "\x04\x80\x80", 3); // Field 1 padding
|
||||
memcpy(cbbuffer+3, "\x05\x80\x80", 3); // Field 2 padding
|
||||
|
||||
writeraw(cbheader,10,&wbout1);
|
||||
writeraw(cbbuffer,3*cbcount, &wbout1);
|
||||
|
||||
if (ccx_options.send_to_srv)
|
||||
{
|
||||
net_send_cc(cbheader, 10);
|
||||
net_send_cc(cbbuffer, 3*cbcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeraw(cbheader,10, wbout1);
|
||||
writeraw(cbbuffer,3*cbcount, wbout1);
|
||||
}
|
||||
|
||||
cbcount = 0;
|
||||
cbempty = 0;
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#include "utility.h"
|
||||
|
||||
static int inputfile_capacity=0;
|
||||
static int inputfile_capacity=0;
|
||||
|
||||
static const char *DEF_VAL_STARTCREDITSNOTBEFORE="0";
|
||||
static const char *DEF_VAL_STARTCREDITSNOTAFTER="5:00"; // To catch the theme after the teaser in TV shows
|
||||
@@ -54,7 +55,6 @@ int stringztoms (const char *s, struct ccx_boundary_time *bt)
|
||||
bt->time_in_ms=secs*1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_cap_file (char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -107,16 +107,16 @@ int isanumber (char *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parsedelay (char *par)
|
||||
int parsedelay (struct ccx_s_options *opt, char *par)
|
||||
{
|
||||
int sign=0;
|
||||
int sign=0;
|
||||
char *c=par;
|
||||
while (*c)
|
||||
{
|
||||
if (*c=='-' || *c=='+')
|
||||
{
|
||||
if (c!=par) // Sign only at the beginning
|
||||
return 1;
|
||||
return 1;
|
||||
if (*c=='-')
|
||||
sign=1;
|
||||
}
|
||||
@@ -124,37 +124,37 @@ int parsedelay (char *par)
|
||||
{
|
||||
if (!isdigit (*c))
|
||||
return 1;
|
||||
subs_delay=subs_delay*10 + (*c-'0');
|
||||
opt->subs_delay = opt->subs_delay*10 + (*c-'0');
|
||||
}
|
||||
c++;
|
||||
}
|
||||
if (sign)
|
||||
subs_delay=-subs_delay;
|
||||
opt->subs_delay =- opt->subs_delay;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int append_file_to_queue (char *filename)
|
||||
int append_file_to_queue (struct ccx_s_options *opt,char *filename)
|
||||
{
|
||||
char *c=(char *) malloc (strlen (filename)+1);
|
||||
if (c==NULL)
|
||||
return -1;
|
||||
return -1;
|
||||
strcpy (c,filename);
|
||||
if (inputfile_capacity<=num_input_files)
|
||||
if (inputfile_capacity<=opt->num_input_files)
|
||||
{
|
||||
inputfile_capacity+=10;
|
||||
inputfile=(char **) realloc (inputfile,sizeof (char *) * inputfile_capacity);
|
||||
if (inputfile==NULL)
|
||||
opt->inputfile=(char **) realloc (opt->inputfile,sizeof (char *) * inputfile_capacity);
|
||||
if (opt->inputfile==NULL)
|
||||
{
|
||||
free(c);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
inputfile[num_input_files]=c;
|
||||
num_input_files++;
|
||||
opt->inputfile[opt->num_input_files]=c;
|
||||
opt->num_input_files++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_file_sequence (char *filename)
|
||||
int add_file_sequence (struct ccx_s_options *opt, char *filename)
|
||||
{
|
||||
int m,n;
|
||||
n=strlen (filename)-1;
|
||||
@@ -162,7 +162,7 @@ int add_file_sequence (char *filename)
|
||||
while (n>=0 && !isdigit (filename[n]))
|
||||
n--;
|
||||
if (n==-1) // None. No expansion needed
|
||||
return append_file_to_queue(filename);
|
||||
return append_file_to_queue(opt, filename);
|
||||
m=n;
|
||||
while (m>=0 && isdigit (filename[m]))
|
||||
m--;
|
||||
@@ -187,7 +187,7 @@ int add_file_sequence (char *filename)
|
||||
if (f==NULL) // Doesn't exist or we can't read it. We're done
|
||||
break;
|
||||
fclose (f);
|
||||
if (append_file_to_queue (filename)) // Memory panic
|
||||
if (append_file_to_queue (opt, filename)) // Memory panic
|
||||
{
|
||||
free(num);
|
||||
free(temp);
|
||||
@@ -218,7 +218,7 @@ void set_output_format (const char *format)
|
||||
|
||||
if (strcmp (format,"srt")==0)
|
||||
ccx_options.write_format=CCX_OF_SRT;
|
||||
else if (strcmp (format,"sami")==0 || strcmp (format,"smi")==0)
|
||||
else if (strcmp (format,"sami")==0 || strcmp (format,"smi")==0)
|
||||
ccx_options.write_format=CCX_OF_SAMI;
|
||||
else if (strcmp (format,"transcript")==0 || strcmp (format,"txt")==0)
|
||||
{
|
||||
@@ -230,12 +230,14 @@ void set_output_format (const char *format)
|
||||
if (ccx_options.date_format==ODF_NONE)
|
||||
ccx_options.date_format=ODF_HHMMSSMS;
|
||||
// Sets the right things so that timestamps and the mode are printed.
|
||||
ccx_options.transcript_settings.showStartTime = 1;
|
||||
ccx_options.transcript_settings.showEndTime = 1;
|
||||
ccx_options.transcript_settings.showCC = 0;
|
||||
ccx_options.transcript_settings.showMode = 1;
|
||||
if (!ccx_options.transcript_settings.isFinal){
|
||||
ccx_options.transcript_settings.showStartTime = 1;
|
||||
ccx_options.transcript_settings.showEndTime = 1;
|
||||
ccx_options.transcript_settings.showCC = 0;
|
||||
ccx_options.transcript_settings.showMode = 1;
|
||||
}
|
||||
}
|
||||
else if (strcmp (format,"report")==0)
|
||||
else if (strcmp (format,"report")==0)
|
||||
{
|
||||
ccx_options.write_format=CCX_OF_NULL;
|
||||
ccx_options.messages_target=0;
|
||||
@@ -258,7 +260,7 @@ void set_output_format (const char *format)
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "Unknown output file format: %s\n", format);
|
||||
}
|
||||
|
||||
void set_input_format (const char *format)
|
||||
void set_input_format (struct ccx_s_options *opt, const char *format)
|
||||
{
|
||||
if (ccx_options.input_source == CCX_DS_TCP && strcmp(format, "bin")!=0)
|
||||
{
|
||||
@@ -269,24 +271,24 @@ void set_input_format (const char *format)
|
||||
while (*format=='-')
|
||||
format++;
|
||||
if (strcmp (format,"es")==0) // Does this actually do anything?
|
||||
auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
opt->auto_stream = CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
else if (strcmp (format,"ts")==0)
|
||||
auto_stream = CCX_SM_TRANSPORT;
|
||||
opt->auto_stream = CCX_SM_TRANSPORT;
|
||||
else if (strcmp (format,"ps")==0 || strcmp (format,"nots")==0)
|
||||
auto_stream = CCX_SM_PROGRAM;
|
||||
opt->auto_stream = CCX_SM_PROGRAM;
|
||||
else if (strcmp (format,"asf")==0 || strcmp (format,"dvr-ms")==0)
|
||||
auto_stream = CCX_SM_ASF;
|
||||
opt->auto_stream = CCX_SM_ASF;
|
||||
else if (strcmp (format,"wtv")==0)
|
||||
auto_stream = CCX_SM_WTV;
|
||||
opt->auto_stream = CCX_SM_WTV;
|
||||
else if (strcmp (format,"raw")==0)
|
||||
auto_stream = CCX_SM_MCPOODLESRAW;
|
||||
opt->auto_stream = CCX_SM_MCPOODLESRAW;
|
||||
else if (strcmp (format,"bin")==0)
|
||||
auto_stream = CCX_SM_RCWT;
|
||||
opt->auto_stream = CCX_SM_RCWT;
|
||||
else if (strcmp (format,"mp4")==0)
|
||||
auto_stream = CCX_SM_MP4;
|
||||
opt->auto_stream = CCX_SM_MP4;
|
||||
#ifdef WTV_DEBUG
|
||||
else if (strcmp (format,"hex")==0)
|
||||
auto_stream = CCX_SM_HEX_DUMP;
|
||||
opt->auto_stream = CCX_SM_HEX_DUMP;
|
||||
#endif
|
||||
else
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "Unknown input file format: %s\n", format);
|
||||
@@ -346,7 +348,7 @@ void usage (void)
|
||||
mprint (" -1, -2, -12: Output Field 1 data, Field 2 data, or both\n");
|
||||
mprint (" (DEFAULT is -1)\n");
|
||||
mprint (" -cc2: When in srt/sami mode, process captions in channel 2\n");
|
||||
mprint (" instead channel 1.\n");
|
||||
mprint (" instead of channel 1.\n");
|
||||
mprint ("-svc --service N,N...: Enabled CEA-708 captions processing for the listed\n");
|
||||
mprint (" services. The parameter is a command delimited list\n");
|
||||
mprint (" of services numbers, such as \"1,2\" to process the\n");
|
||||
@@ -440,8 +442,8 @@ void usage (void)
|
||||
mprint (" software to convert *.wtv to *.dvr-ms. For analog NTSC\n");
|
||||
mprint (" recordings the CC information is marked as digital\n");
|
||||
mprint (" captions. Use this switch only when needed.\n");
|
||||
mprint (" -wtvmpeg2: Read the captions from the MPEG2 video stream rather\n");
|
||||
mprint (" than the captions stream in WTV files\n");
|
||||
mprint (" -wtvmpeg2: Read the captions from the MPEG2 video stream rather\n");
|
||||
mprint (" than the captions stream in WTV files\n");
|
||||
mprint (" -pn --program-number: In TS mode, specifically select a program to process.\n");
|
||||
mprint (" Not needed if the TS only has one. If this parameter\n");
|
||||
mprint (" is not specified and CCExtractor detects more than one\n");
|
||||
@@ -475,6 +477,13 @@ void usage (void)
|
||||
mprint (" affects Teletext in timed transcript with -datets.\n");
|
||||
mprint ("\n");
|
||||
mprint ("Options that affect what kind of output will be produced:\n");
|
||||
mprint(" -bom: Append a BOM (Byte Order Mark) to output files.");
|
||||
mprint(" Note that most text processing tools in linux will not");
|
||||
mprint(" like BOM.");
|
||||
mprint(" This is the default in Windows builds.");
|
||||
mprint(" -nobom: Do not append a BOM (Byte Order Mark) to output files.");
|
||||
mprint(" Note that this may break files when using Windows.");
|
||||
mprint(" This is the default in non-Windows builds.");
|
||||
mprint (" -unicode: Encode subtitles in Unicode instead of Latin-1.\n");
|
||||
mprint (" -utf8: Encode subtitles in UTF-8 (no longer needed.\n");
|
||||
mprint (" because UTF-8 is now the default).\n");
|
||||
@@ -732,7 +741,7 @@ void parse_708services (char *s)
|
||||
while (*c && !isdigit (*c))
|
||||
c++;
|
||||
if (!*c) // We're done
|
||||
break;
|
||||
break;
|
||||
e=c;
|
||||
while (isdigit (*e))
|
||||
e++;
|
||||
@@ -790,17 +799,17 @@ void init_option (struct ccx_s_options *option)
|
||||
option->ts_forced_program_selected = 1;
|
||||
}
|
||||
|
||||
void parse_parameters (int argc, char *argv[])
|
||||
void parse_parameters (struct ccx_s_options *opt, int argc, char *argv[])
|
||||
{
|
||||
char *cea708_service_list=NULL; // List CEA-708 services
|
||||
|
||||
// Sensible default values for credits
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &ccx_options.startcreditsnotbefore);
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &ccx_options.startcreditsnotafter);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &ccx_options.startcreditsforatleast);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &ccx_options.startcreditsforatmost);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &ccx_options.endcreditsforatleast);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &ccx_options.endcreditsforatmost);
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTBEFORE, &opt->startcreditsnotbefore);
|
||||
stringztoms (DEF_VAL_STARTCREDITSNOTAFTER, &opt->startcreditsnotafter);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATLEAST, &opt->startcreditsforatleast);
|
||||
stringztoms (DEF_VAL_STARTCREDITSFORATMOST, &opt->startcreditsforatmost);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATLEAST, &opt->endcreditsforatleast);
|
||||
stringztoms (DEF_VAL_ENDCREDITSFORATMOST, &opt->endcreditsforatmost);
|
||||
|
||||
// Parse parameters
|
||||
for (int i=1; i<argc; i++)
|
||||
@@ -808,8 +817,8 @@ void parse_parameters (int argc, char *argv[])
|
||||
if (strcmp (argv[i], "-")==0 || strcmp(argv[i], "-stdin") == 0)
|
||||
{
|
||||
|
||||
ccx_options.input_source=CCX_DS_STDIN;
|
||||
ccx_options.live_stream=-1;
|
||||
opt->input_source=CCX_DS_STDIN;
|
||||
opt->live_stream=-1;
|
||||
continue;
|
||||
}
|
||||
if (argv[i][0]!='-')
|
||||
@@ -817,12 +826,12 @@ void parse_parameters (int argc, char *argv[])
|
||||
int rc;
|
||||
if (argv[i][strlen (argv[i])-1]!='+')
|
||||
{
|
||||
rc=append_file_to_queue (argv[i]);
|
||||
rc=append_file_to_queue (opt, argv[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[i][strlen (argv[i])-1]=0;
|
||||
rc=add_file_sequence (argv[i]);
|
||||
rc=add_file_sequence (opt, argv[i]);
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
@@ -861,6 +870,14 @@ void parse_parameters (int argc, char *argv[])
|
||||
ccx_options.nofontcolor=1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-bom") == 0){
|
||||
ccx_options.no_bom = 0;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "-nobom") == 0){
|
||||
ccx_options.no_bom = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-nots")==0 ||
|
||||
strcmp (argv[i],"--notypesetting")==0)
|
||||
{
|
||||
@@ -878,12 +895,12 @@ void parse_parameters (int argc, char *argv[])
|
||||
strcmp (argv[i],"-mp4")==0 ||
|
||||
strcmp (argv[i],"--dvr-ms")==0 )
|
||||
{
|
||||
set_input_format (argv[i]);
|
||||
set_input_format (opt, argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (strncmp (argv[i],"-in=", 4)==0)
|
||||
{
|
||||
set_input_format (argv[i]+4);
|
||||
set_input_format (opt, argv[i]+4);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1031,19 +1048,19 @@ void parse_parameters (int argc, char *argv[])
|
||||
ccx_options.extract = 12;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-gt")==0 ||
|
||||
if (strcmp (argv[i],"-gt")==0 ||
|
||||
strcmp (argv[i],"--goptime")==0)
|
||||
{
|
||||
ccx_options.use_gop_as_pts = 1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-nogt")==0 ||
|
||||
if (strcmp (argv[i],"-nogt")==0 ||
|
||||
strcmp (argv[i],"--nogoptime")==0)
|
||||
{
|
||||
ccx_options.use_gop_as_pts = -1; // Don't use even if we would want to
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-fp")==0 ||
|
||||
if (strcmp (argv[i],"-fp")==0 ||
|
||||
strcmp (argv[i],"--fixpadding")==0)
|
||||
{
|
||||
ccx_options.fix_padding = 1;
|
||||
@@ -1054,7 +1071,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
MPEG_CLOCK_FREQ=90090;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-noru")==0 ||
|
||||
if (strcmp (argv[i],"-noru")==0 ||
|
||||
strcmp (argv[i],"--norollup")==0)
|
||||
{
|
||||
ccx_options.settings_608.no_rollup = 1;
|
||||
@@ -1108,7 +1125,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
if (strcmp (argv[i],"--program-number")==0 ||
|
||||
strcmp (argv[i],"-pn")==0)
|
||||
{
|
||||
if (i==argc-1 // Means no following argument
|
||||
if (i==argc-1 // Means no following argument
|
||||
|| !isanumber (argv[i+1])) // Means is not a number
|
||||
ccx_options.ts_forced_program = (unsigned)-1; // Autodetect
|
||||
else
|
||||
@@ -1127,7 +1144,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
if (strcmp (argv[i],"--stream")==0 ||
|
||||
strcmp (argv[i],"-s")==0)
|
||||
{
|
||||
if (i==argc-1 // Means no following argument
|
||||
if (i==argc-1 // Means no following argument
|
||||
|| !isanumber (argv[i+1])) // Means is not a number
|
||||
ccx_options.live_stream=-1; // Live stream without timeout
|
||||
else
|
||||
@@ -1152,14 +1169,14 @@ void parse_parameters (int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-delay")==0 && i<argc-1)
|
||||
{
|
||||
if (parsedelay (argv[i+1]))
|
||||
if (parsedelay (opt, argv[i+1]))
|
||||
{
|
||||
fatal (EXIT_MALFORMED_PARAMETER, "-delay only accept integers (such as -300 or 300)\n");
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if ((strcmp (argv[i],"-scr")==0 ||
|
||||
if ((strcmp (argv[i],"-scr")==0 ||
|
||||
strcmp (argv[i],"--screenfuls")==0) && i<argc-1)
|
||||
{
|
||||
ccx_options.settings_608.screens_to_process = atoi_hex(argv[i + 1]);
|
||||
@@ -1207,7 +1224,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
{
|
||||
if (ccx_options.messages_target==1) // Only change this if still stdout. -quiet could set it to 0 for example
|
||||
ccx_options.messages_target=2; // stderr
|
||||
cc_to_stdout=1;
|
||||
opt->cc_to_stdout=1;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-quiet")==0)
|
||||
@@ -1227,7 +1244,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-deblev")==0)
|
||||
{
|
||||
ccx_options.debug_mask |= CCX_DMT_LEVENSHTEIN;
|
||||
ccx_options.debug_mask |= CCX_DMT_LEVENSHTEIN;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-levdistmincnt")==0 && i<argc-1)
|
||||
@@ -1247,7 +1264,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
ccx_options.debug_mask |= CCX_DMT_708;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-goppts")==0)
|
||||
if (strcmp (argv[i],"-goppts")==0)
|
||||
{
|
||||
ccx_options.debug_mask |= CCX_DMT_TIME;
|
||||
continue;
|
||||
@@ -1259,6 +1276,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-xds")==0)
|
||||
{
|
||||
// XDS can be set regardless of -UCLA (isFinal) usage.
|
||||
ccx_options.transcript_settings.xds = 1;
|
||||
continue;
|
||||
}
|
||||
@@ -1372,13 +1390,13 @@ void parse_parameters (int argc, char *argv[])
|
||||
}
|
||||
if (strcmp (argv[i],"-o1")==0 && i<argc-1)
|
||||
{
|
||||
wbout1.filename=argv[i+1];
|
||||
opt->wbout1.filename=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-o2")==0 && i<argc-1)
|
||||
{
|
||||
wbout2.filename=argv[i+1];
|
||||
opt->wbout2.filename=argv[i+1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
@@ -1421,11 +1439,15 @@ void parse_parameters (int argc, char *argv[])
|
||||
if (strcmp (argv[i],"-UCLA")==0 || strcmp (argv[i],"-ucla")==0)
|
||||
{
|
||||
ccx_options.millis_separator='.';
|
||||
ccx_options.transcript_settings.showStartTime = 1;
|
||||
ccx_options.transcript_settings.showEndTime = 1;
|
||||
ccx_options.transcript_settings.showCC = 1;
|
||||
ccx_options.transcript_settings.showMode = 1;
|
||||
ccx_options.transcript_settings.relativeTimestamp = 0;
|
||||
ccx_options.no_bom = 1;
|
||||
if (!ccx_options.transcript_settings.isFinal){
|
||||
ccx_options.transcript_settings.showStartTime = 1;
|
||||
ccx_options.transcript_settings.showEndTime = 1;
|
||||
ccx_options.transcript_settings.showCC = 1;
|
||||
ccx_options.transcript_settings.showMode = 1;
|
||||
ccx_options.transcript_settings.relativeTimestamp = 0;
|
||||
ccx_options.transcript_settings.isFinal = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp (argv[i],"-lf")==0 || strcmp (argv[i],"-LF")==0)
|
||||
@@ -1447,7 +1469,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
{
|
||||
uint64_t t = 0;
|
||||
t = atoi_hex(argv[i + 1]);
|
||||
if (t <= 0)
|
||||
if (t <= 0)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
t = time(&now);
|
||||
@@ -1485,13 +1507,18 @@ void parse_parameters (int argc, char *argv[])
|
||||
if (strlen(format) == 7){
|
||||
if (ccx_options.date_format == ODF_NONE)
|
||||
ccx_options.date_format = ODF_HHMMSSMS; // Necessary for displaying times, if any would be used.
|
||||
ccx_options.transcript_settings.showStartTime = format[0]-'0';
|
||||
ccx_options.transcript_settings.showEndTime = format[1] - '0';
|
||||
ccx_options.transcript_settings.showMode = format[2] - '0';
|
||||
ccx_options.transcript_settings.showCC = format[3] - '0';
|
||||
ccx_options.transcript_settings.relativeTimestamp = format[4] - '0';
|
||||
ccx_options.transcript_settings.xds = format[5] - '0';
|
||||
ccx_options.transcript_settings.useColors = format[6] - '0';
|
||||
if (!ccx_options.transcript_settings.isFinal){
|
||||
ccx_options.transcript_settings.showStartTime = format[0] - '0';
|
||||
ccx_options.transcript_settings.showEndTime = format[1] - '0';
|
||||
ccx_options.transcript_settings.showMode = format[2] - '0';
|
||||
ccx_options.transcript_settings.showCC = format[3] - '0';
|
||||
ccx_options.transcript_settings.relativeTimestamp = format[4] - '0';
|
||||
ccx_options.transcript_settings.xds = format[5] - '0';
|
||||
ccx_options.transcript_settings.useColors = format[6] - '0';
|
||||
} else {
|
||||
// Throw exception
|
||||
fatal(EXIT_INCOMPATIBLE_PARAMETERS, "customtxt cannot be set after -UCLA is used!");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
@@ -1565,7 +1592,7 @@ void parse_parameters (int argc, char *argv[])
|
||||
ccx_options.tcpport = argv[i + 1];
|
||||
ccx_options.input_source = CCX_DS_TCP;
|
||||
|
||||
set_input_format("bin");
|
||||
set_input_format(opt, "bin");
|
||||
|
||||
i++;
|
||||
continue;
|
||||
@@ -1591,4 +1618,3 @@ void parse_parameters (int argc, char *argv[])
|
||||
// Unrecognized switches are silently ignored
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
void params_dump(void)
|
||||
void params_dump(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
// Display parsed parameters
|
||||
mprint ("Input: ");
|
||||
switch (ccx_options.input_source)
|
||||
{
|
||||
case CCX_DS_FILE:
|
||||
for (int i=0;i<num_input_files;i++)
|
||||
mprint ("%s%s",inputfile[i],i==(num_input_files-1)?"":",");
|
||||
for (int i=0;i<ctx->num_input_files;i++)
|
||||
mprint ("%s%s",ctx->inputfile[i],i==(ctx->num_input_files-1)?"":",");
|
||||
break;
|
||||
case CCX_DS_STDIN:
|
||||
mprint ("stdin");
|
||||
@@ -25,10 +26,10 @@ void params_dump(void)
|
||||
mprint("Network, TCP/%s", ccx_options.tcpport);
|
||||
break;
|
||||
}
|
||||
mprint ("\n");
|
||||
mprint ("\n");
|
||||
mprint ("[Extract: %d] ", ccx_options.extract);
|
||||
mprint ("[Stream mode: ");
|
||||
switch (auto_stream)
|
||||
switch (ctx->auto_stream)
|
||||
{
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
mprint ("Elementary");
|
||||
@@ -73,7 +74,7 @@ void params_dump(void)
|
||||
else
|
||||
mprint ("Auto ]");
|
||||
mprint (" [Hauppage mode: %s]",ccx_options.hauppauge_mode?"Yes":"No");
|
||||
|
||||
|
||||
mprint (" [Use MythTV code: ");
|
||||
switch (ccx_options.auto_myth)
|
||||
{
|
||||
@@ -113,12 +114,12 @@ void params_dump(void)
|
||||
mprint ("Auto");
|
||||
break;
|
||||
}
|
||||
mprint ("] ");
|
||||
mprint ("] ");
|
||||
mprint ("[Debug: %s] ", (ccx_options.debug_mask & CCX_DMT_VERBOSE) ? "Yes": "No");
|
||||
mprint ("[Buffer input: %s]\n", ccx_options.buffer_input ? "Yes": "No");
|
||||
mprint ("[Use pic_order_cnt_lsb for H.264: %s] ", ccx_options.usepicorder ? "Yes": "No");
|
||||
mprint("[Print CC decoder traces: %s]\n", (ccx_options.debug_mask & CCX_DMT_DECODER_608) ? "Yes" : "No");
|
||||
mprint ("[Target format: %s] ",extension);
|
||||
mprint ("[Target format: %s] ",ctx->extension);
|
||||
mprint ("[Encoding: ");
|
||||
switch (ccx_options.encoding)
|
||||
{
|
||||
@@ -133,7 +134,7 @@ void params_dump(void)
|
||||
break;
|
||||
}
|
||||
mprint ("] ");
|
||||
mprint ("[Delay: %lld] ",subs_delay);
|
||||
mprint ("[Delay: %lld] ",ctx->subs_delay);
|
||||
|
||||
mprint ("[Trim lines: %s]\n",ccx_options.trim_subs?"Yes":"No");
|
||||
mprint ("[Add font color data: %s] ", ccx_options.nofontcolor? "No" : "Yes");
|
||||
@@ -179,40 +180,48 @@ void params_dump(void)
|
||||
mprint ("%d]\n",tlt_config.page);
|
||||
else
|
||||
mprint ("Autodetect]\n");
|
||||
mprint ("Start credits text: [%s]\n",
|
||||
mprint ("Start credits text: [%s]\n",
|
||||
ccx_options.start_credits_text?ccx_options.start_credits_text:"None");
|
||||
if (ccx_options.start_credits_text)
|
||||
{
|
||||
mprint ("Start credits time: Insert between [%ld] and [%ld] seconds\n",
|
||||
(long) (ccx_options.startcreditsnotbefore.time_in_ms/1000),
|
||||
(long) (ccx_options.startcreditsnotbefore.time_in_ms/1000),
|
||||
(long) (ccx_options.startcreditsnotafter.time_in_ms/1000)
|
||||
);
|
||||
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
|
||||
(long) (ccx_options.startcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.startcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.startcreditsforatmost.time_in_ms/1000)
|
||||
);
|
||||
}
|
||||
if (ccx_options.end_credits_text)
|
||||
{
|
||||
mprint ("End credits text: [%s]\n",
|
||||
mprint ("End credits text: [%s]\n",
|
||||
ccx_options.end_credits_text?ccx_options.end_credits_text:"None");
|
||||
mprint (" Display for at least [%ld] and at most [%ld] seconds\n",
|
||||
(long) (ccx_options.endcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.endcreditsforatleast.time_in_ms/1000),
|
||||
(long) (ccx_options.endcreditsforatmost.time_in_ms/1000)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void print_file_report(void)
|
||||
void print_file_report(struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
struct lib_cc_decode *dec_ctx = NULL;
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
#define Y_N(cond) ((cond) ? "Yes" : "No")
|
||||
|
||||
printf("File: ");
|
||||
switch (ccx_options.input_source)
|
||||
{
|
||||
case CCX_DS_FILE:
|
||||
printf("%s\n", inputfile[current_file]);
|
||||
if (ctx->current_file < 0)
|
||||
{
|
||||
printf("file is not openened yet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%s\n", ctx->inputfile[ctx->current_file]);
|
||||
break;
|
||||
case CCX_DS_STDIN:
|
||||
printf("stdin\n");
|
||||
@@ -224,12 +233,12 @@ void print_file_report(void)
|
||||
}
|
||||
|
||||
printf("Stream Mode: ");
|
||||
switch (stream_mode)
|
||||
switch (ctx->stream_mode)
|
||||
{
|
||||
case CCX_SM_TRANSPORT:
|
||||
printf("Transport Stream\n");
|
||||
|
||||
printf("Program Count: %d\n", file_report.program_cnt);
|
||||
printf("Program Count: %d\n", ctx->freport.program_cnt);
|
||||
|
||||
printf("Program Numbers: ");
|
||||
for (int i = 0; i < pmt_array_length; i++)
|
||||
@@ -241,28 +250,28 @@ void print_file_report(void)
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < 65536; i++)
|
||||
for (int i = 0; i < 65536; i++)
|
||||
{
|
||||
if (PIDs_programs[i] == 0)
|
||||
if (ctx->PIDs_programs[i] == 0)
|
||||
continue;
|
||||
|
||||
printf("PID: %u, Program: %u, ", i, PIDs_programs[i]->program_number);
|
||||
printf("PID: %u, Program: %u, ", i, ctx->PIDs_programs[i]->program_number);
|
||||
int j;
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
{
|
||||
if (file_report.dvb_sub_pid[j] == i)
|
||||
if (ctx->freport.dvb_sub_pid[j] == i)
|
||||
{
|
||||
printf("DVB Subtitles\n");
|
||||
break;
|
||||
}
|
||||
if (file_report.tlt_sub_pid[j] == i)
|
||||
if (ctx->freport.tlt_sub_pid[j] == i)
|
||||
{
|
||||
printf("Teletext Subtitles\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == SUB_STREAMS_CNT)
|
||||
printf("%s\n", desc[PIDs_programs[i]->printable_stream_type]);
|
||||
printf("%s\n", desc[ctx->PIDs_programs[i]->printable_stream_type]);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -277,7 +286,7 @@ void print_file_report(void)
|
||||
break;
|
||||
case CCX_SM_ELEMENTARY_OR_NOT_FOUND:
|
||||
printf("Not Found\n");
|
||||
break;
|
||||
break;
|
||||
case CCX_SM_MP4:
|
||||
printf("MP4\n");
|
||||
break;
|
||||
@@ -296,29 +305,29 @@ void print_file_report(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ccx_bufferdatatype == CCX_PES &&
|
||||
(stream_mode == CCX_SM_TRANSPORT ||
|
||||
stream_mode == CCX_SM_PROGRAM ||
|
||||
stream_mode == CCX_SM_ASF ||
|
||||
stream_mode == CCX_SM_WTV))
|
||||
if (ccx_bufferdatatype == CCX_PES &&
|
||||
(ctx->stream_mode == CCX_SM_TRANSPORT ||
|
||||
ctx->stream_mode == CCX_SM_PROGRAM ||
|
||||
ctx->stream_mode == CCX_SM_ASF ||
|
||||
ctx->stream_mode == CCX_SM_WTV))
|
||||
{
|
||||
printf("Width: %u\n", file_report.width);
|
||||
printf("Height: %u\n", file_report.height);
|
||||
printf("Aspect Ratio: %s\n", aspect_ratio_types[file_report.aspect_ratio]);
|
||||
printf("Frame Rate: %s\n", framerates_types[file_report.frame_rate]);
|
||||
printf("Width: %u\n", ctx->freport.width);
|
||||
printf("Height: %u\n", ctx->freport.height);
|
||||
printf("Aspect Ratio: %s\n", aspect_ratio_types[ctx->freport.aspect_ratio]);
|
||||
printf("Frame Rate: %s\n", framerates_types[ctx->freport.frame_rate]);
|
||||
}
|
||||
|
||||
if (file_report.program_cnt > 1)
|
||||
if (ctx->freport.program_cnt > 1)
|
||||
printf("//////// Program #%u: ////////\n", TS_program_number);
|
||||
|
||||
printf("DVB Subtitles: ");
|
||||
int j;
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
{
|
||||
unsigned pid = file_report.dvb_sub_pid[j];
|
||||
unsigned pid = ctx->freport.dvb_sub_pid[j];
|
||||
if (pid == 0)
|
||||
continue;
|
||||
if (PIDs_programs[pid]->program_number == TS_program_number)
|
||||
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
|
||||
{
|
||||
printf("Yes\n");
|
||||
break;
|
||||
@@ -328,17 +337,17 @@ void print_file_report(void)
|
||||
printf("No\n");
|
||||
|
||||
printf("Teletext: ");
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
for (j = 0; j < SUB_STREAMS_CNT; j++)
|
||||
{
|
||||
unsigned pid = file_report.tlt_sub_pid[j];
|
||||
unsigned pid = ctx->freport.tlt_sub_pid[j];
|
||||
if (pid == 0)
|
||||
continue;
|
||||
if (PIDs_programs[pid]->program_number == TS_program_number)
|
||||
if (ctx->PIDs_programs[pid]->program_number == TS_program_number)
|
||||
{
|
||||
printf("Yes\n");
|
||||
|
||||
printf("Pages With Subtitles: ");
|
||||
for (int i = 0; i < MAX_TLT_PAGES; i++)
|
||||
for (int i = 0; i < MAX_TLT_PAGES; i++)
|
||||
{
|
||||
if (seen_sub_page[i] == 0)
|
||||
continue;
|
||||
@@ -352,42 +361,42 @@ void print_file_report(void)
|
||||
if (j == SUB_STREAMS_CNT)
|
||||
printf("No\n");
|
||||
|
||||
printf("EIA-608: %s\n", Y_N(cc_stats[0] > 0 || cc_stats[1] > 0));
|
||||
printf("EIA-608: %s\n", Y_N(dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0));
|
||||
|
||||
if (cc_stats[0] > 0 || cc_stats[1] > 0)
|
||||
if (dec_ctx->cc_stats[0] > 0 || dec_ctx->cc_stats[1] > 0)
|
||||
{
|
||||
printf("XDS: %s\n", Y_N(file_report.data_from_608.xds));
|
||||
printf("XDS: %s\n", Y_N(ctx->freport.data_from_608->xds));
|
||||
|
||||
printf("CC1: %s\n", Y_N(file_report.data_from_608.cc_channels[0]));
|
||||
printf("CC2: %s\n", Y_N(file_report.data_from_608.cc_channels[1]));
|
||||
printf("CC3: %s\n", Y_N(file_report.data_from_608.cc_channels[2]));
|
||||
printf("CC4: %s\n", Y_N(file_report.data_from_608.cc_channels[3]));
|
||||
printf("CC1: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[0]));
|
||||
printf("CC2: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[1]));
|
||||
printf("CC3: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[2]));
|
||||
printf("CC4: %s\n", Y_N(ctx->freport.data_from_608->cc_channels[3]));
|
||||
}
|
||||
|
||||
printf("CEA-708: %s\n", Y_N(cc_stats[2] > 0 || cc_stats[3] > 0));
|
||||
printf("CEA-708: %s\n", Y_N(dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0));
|
||||
|
||||
if (cc_stats[2] > 0 || cc_stats[3] > 0)
|
||||
if (dec_ctx->cc_stats[2] > 0 || dec_ctx->cc_stats[3] > 0)
|
||||
{
|
||||
printf("Services: ");
|
||||
for (int i = 0; i < CCX_DECODERS_708_MAX_SERVICES; i++)
|
||||
for (int i = 0; i < CCX_DECODERS_708_MAX_SERVICES; i++)
|
||||
{
|
||||
if (file_report.data_from_708.services[i] == 0)
|
||||
if (ctx->freport.data_from_708->services[i] == 0)
|
||||
continue;
|
||||
printf("%d ", i);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Primary Language Present: %s\n", Y_N(file_report.data_from_708.services[1]));
|
||||
printf("Primary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[1]));
|
||||
|
||||
printf("Secondary Language Present: %s\n", Y_N(file_report.data_from_708.services[2]));
|
||||
printf("Secondary Language Present: %s\n", Y_N(ctx->freport.data_from_708->services[2]));
|
||||
}
|
||||
|
||||
printf("MPEG-4 Timed Text: %s\n", Y_N(file_report.mp4_cc_track_cnt));
|
||||
if (file_report.mp4_cc_track_cnt) {
|
||||
printf("MPEG-4 Timed Text tracks count: %d\n", file_report.mp4_cc_track_cnt);
|
||||
printf("MPEG-4 Timed Text: %s\n", Y_N(ctx->freport.mp4_cc_track_cnt));
|
||||
if (ctx->freport.mp4_cc_track_cnt) {
|
||||
printf("MPEG-4 Timed Text tracks count: %d\n", ctx->freport.mp4_cc_track_cnt);
|
||||
}
|
||||
|
||||
memset(&file_report, 0, sizeof (struct file_report_t));
|
||||
memset(&ctx->freport, 0, sizeof (struct file_report));
|
||||
|
||||
#undef Y_N
|
||||
}
|
||||
154
src/lib_ccx/sequencing.c
Normal file
154
src/lib_ccx/sequencing.c
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
|
||||
// Defined by the maximum number of B-Frames per anchor frame.
|
||||
//#define MAXBFRAMES 50 - from lib_ccx.h
|
||||
// They can be (temporally) before or after the anchor. Reserve
|
||||
// enough space.
|
||||
//#define SORTBUF (2*MAXBFRAMES+1) - from lib_ccx.h
|
||||
// B-Frames can be (temporally) before or after the anchor
|
||||
int cc_data_count[SORTBUF];
|
||||
// Store fts;
|
||||
static LLONG cc_fts[SORTBUF];
|
||||
// Store HD CC packets
|
||||
unsigned char cc_data_pkts[SORTBUF][10*31*3+1]; // *10, because MP4 seems to have different limits
|
||||
|
||||
// Set to true if data is buffered
|
||||
int has_ccdata_buffered = 0;
|
||||
// The sequence number of the current anchor frame. All currently read
|
||||
// B-Frames belong to this I- or P-frame.
|
||||
static int anchor_seq_number = -1;
|
||||
|
||||
void init_hdcc (void)
|
||||
{
|
||||
for (int j=0; j<SORTBUF; j++)
|
||||
{
|
||||
cc_data_count[j] = 0;
|
||||
cc_fts[j] = 0;
|
||||
}
|
||||
memset(cc_data_pkts, 0, SORTBUF*(31*3+1));
|
||||
has_ccdata_buffered = 0;
|
||||
}
|
||||
|
||||
// Buffer caption blocks for later sorting/flushing.
|
||||
void store_hdcc(struct lib_ccx_ctx *ctx, unsigned char *cc_data, int cc_count, int sequence_number, LLONG current_fts_now,struct cc_subtitle *sub)
|
||||
{
|
||||
// Uninitialized?
|
||||
if (anchor_seq_number < 0)
|
||||
{
|
||||
anchor_hdcc( sequence_number);
|
||||
}
|
||||
|
||||
int seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
|
||||
|
||||
if (seq_index < 0 || seq_index > 2*MAXBFRAMES)
|
||||
{
|
||||
// Maybe missing an anchor frame - try to recover
|
||||
dbg_print(CCX_DMT_VERBOSE, "Too many B-frames, or missing anchor frame. Trying to recover ..\n");
|
||||
|
||||
process_hdcc(ctx, sub);
|
||||
anchor_hdcc( sequence_number);
|
||||
seq_index = sequence_number - anchor_seq_number + MAXBFRAMES;
|
||||
}
|
||||
|
||||
has_ccdata_buffered = 1;
|
||||
|
||||
// In GOP mode the fts is set only once for the whole GOP. Recreate
|
||||
// the right time according to the sequence number.
|
||||
if (ccx_options.use_gop_as_pts==1)
|
||||
{
|
||||
current_fts_now += (LLONG) (sequence_number*1000.0/current_fps);
|
||||
}
|
||||
|
||||
if (cc_count)
|
||||
{
|
||||
if (cc_data)
|
||||
{
|
||||
// Changed by CFS to concat, i.e. don't assume there's no data already for this seq_index.
|
||||
// Needed at least for MP4 samples. // TODO: make sure we don't overflow
|
||||
cc_fts[seq_index] = current_fts_now; // CFS: Maybe do even if there's no data?
|
||||
if (ctx->stream_mode!=CCX_SM_MP4) // CFS: Very ugly hack, but looks like overwriting is needed for at least some ES
|
||||
cc_data_count[seq_index] = 0;
|
||||
memcpy(cc_data_pkts[seq_index]+cc_data_count[seq_index]*3, cc_data, cc_count*3+1);
|
||||
}
|
||||
cc_data_count[seq_index] += cc_count;
|
||||
}
|
||||
// DEBUG STUFF
|
||||
/*
|
||||
printf("\nCC blocks, channel 0:\n");
|
||||
for ( int i=0; i < cc_count*3; i+=3)
|
||||
{
|
||||
printf("%s", debug_608toASC( cc_data+i, 0) );
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
}
|
||||
|
||||
// Set a new anchor frame that new B-frames refer to.
|
||||
void anchor_hdcc(int seq)
|
||||
{
|
||||
// Re-init the index
|
||||
anchor_seq_number = seq;
|
||||
}
|
||||
|
||||
// Sort/flash caption block buffer
|
||||
void process_hdcc (struct lib_ccx_ctx *ctx, struct cc_subtitle *sub)
|
||||
{
|
||||
// Remember the current value
|
||||
LLONG store_fts_now = fts_now;
|
||||
struct lib_cc_decode *dec_ctx;
|
||||
int reset_cb = -1;
|
||||
|
||||
dbg_print(CCX_DMT_VERBOSE, "Flush HD caption blocks\n");
|
||||
dec_ctx = ctx->dec_ctx;
|
||||
|
||||
for (int seq=0; seq<SORTBUF; seq++)
|
||||
{
|
||||
// We rely on this.
|
||||
if (ccx_bufferdatatype == CCX_H264)
|
||||
reset_cb = 1;
|
||||
|
||||
// If fts_now is unchanged we rely on cc block counting,
|
||||
// otherwise reset counters as they get changed by do_cb()
|
||||
// below. This only happens when current_pts does not get
|
||||
// updated, like it used do happen for elementary streams.
|
||||
// Since use_gop_as_pts this is not needed anymore, but left
|
||||
// here for posterity.
|
||||
if (reset_cb < 0 && cc_fts[seq] && seq<SORTBUF-1 && cc_fts[seq+1])
|
||||
{
|
||||
if (cc_fts[seq] != cc_fts[seq+1])
|
||||
reset_cb = 1;
|
||||
else
|
||||
reset_cb = 0;
|
||||
}
|
||||
if (reset_cb == 1)
|
||||
{
|
||||
cb_field1 = 0;
|
||||
cb_field2 = 0;
|
||||
cb_708 = 0;
|
||||
}
|
||||
|
||||
// Skip sequence numbers without data
|
||||
if (cc_data_count[seq] == 0)
|
||||
continue;
|
||||
|
||||
if (cc_data_pkts[seq][cc_data_count[seq]*3]!=0xFF)
|
||||
{
|
||||
// This is not optional. Something is wrong.
|
||||
dbg_print(CCX_DMT_VERBOSE, "Missing 0xFF marker at end\n");
|
||||
// A "continue;" here would ignore this caption, but we
|
||||
// process it.
|
||||
}
|
||||
|
||||
// Re-create original time
|
||||
fts_now = cc_fts[seq];
|
||||
process_cc_data( dec_ctx, cc_data_pkts[seq], cc_data_count[seq], sub);
|
||||
|
||||
}
|
||||
|
||||
// Restore the value
|
||||
fts_now = store_fts_now;
|
||||
|
||||
// Now that we are done, clean up.
|
||||
init_hdcc();
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <assert.h>
|
||||
#ifdef ENABLE_OCR
|
||||
#include "ocr.h"
|
||||
#undef OCR_DEBUG
|
||||
#endif
|
||||
|
||||
#define CCPL (ccfont2_width / CCW * ccfont2_height / CCH)
|
||||
@@ -333,7 +334,7 @@ void set_spupng_offset(void *ctx,int x,int y)
|
||||
sp->xOffset = x;
|
||||
sp->yOffset = y;
|
||||
}
|
||||
static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
|
||||
int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
|
||||
png_color *palette, png_byte *alpha, int nb_color)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
@@ -430,7 +431,12 @@ static int save_spupng(const char *filename, uint8_t *bitmap, int w, int h,
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* alpha value 255 means completely opaque
|
||||
* alpha value 0 means completely transparent
|
||||
* r g b all 0 means black
|
||||
* r g b all 255 means white
|
||||
*/
|
||||
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
|
||||
uint8_t depth)
|
||||
{
|
||||
@@ -441,167 +447,27 @@ int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
|
||||
palette[i].blue = (clut[i] & 0xff);
|
||||
alpha[i] = ((clut[i] >> 24) & 0xff);
|
||||
}
|
||||
#if OCR_DEBUG
|
||||
ccx_common_logging.log_ftn("Colors present in original Image\n");
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
ccx_common_logging.log_ftn("%02d)r %03d g %03d b %03d a %03d\n",
|
||||
i, palette[i].red, palette[i].green, palette[i].blue, alpha[i]);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct transIntensity
|
||||
{
|
||||
uint8_t *t;
|
||||
png_color *palette;
|
||||
};
|
||||
int check_trans_tn_intensity(const void *p1, const void *p2, void *arg)
|
||||
{
|
||||
struct transIntensity *ti = arg;
|
||||
unsigned char* tmp = (unsigned char*)p1;
|
||||
unsigned char* act = (unsigned char*)p2;
|
||||
unsigned char tmp_i;
|
||||
unsigned char act_i;
|
||||
/** TODO verify that RGB follow ITU-R BT.709
|
||||
* Below fomula is valid only for 709 standurd
|
||||
* Y = 0.2126 R + 0.7152 G + 0.0722 B
|
||||
*/
|
||||
tmp_i = (0.2126 * ti->palette[*tmp].red) + (0.7152 * ti->palette[*tmp].green) + (0.0722 * ti->palette[*tmp].blue);
|
||||
act_i = (0.2126 * ti->palette[*act].red) + (0.7152 * ti->palette[*act].green) + (0.0722 * ti->palette[*act].blue);;
|
||||
|
||||
if (ti->t[*tmp] < ti->t[*act] || (ti->t[*tmp] == ti->t[*act] && tmp_i < act_i))
|
||||
return -1;
|
||||
else if (ti->t[*tmp] == ti->t[*act] && tmp_i == act_i)
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* @param alpha out
|
||||
* @param intensity in
|
||||
* @param palette out should be already initialized
|
||||
* @param bitmap in
|
||||
* @param size in size of bitmap
|
||||
* @param max_color in
|
||||
* @param nb_color in
|
||||
*/
|
||||
int quantize_map(png_byte *alpha, png_color *palette,
|
||||
uint8_t *bitmap, int size, int max_color, int nb_color)
|
||||
{
|
||||
/*
|
||||
* occurrence of color in image
|
||||
*/
|
||||
uint32_t *histogram = NULL;
|
||||
/* intensity ordered table */
|
||||
uint8_t *iot = NULL;
|
||||
/* array of color with most occurrence according to histogram
|
||||
* save index of intensity order table
|
||||
*/
|
||||
uint32_t *mcit = NULL;
|
||||
struct transIntensity ti = { alpha,palette};
|
||||
|
||||
int ret = 0;
|
||||
|
||||
histogram = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!histogram)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
iot = (uint8_t*) malloc(nb_color * sizeof(uint8_t));
|
||||
if (!iot)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mcit = (uint32_t*) malloc(nb_color * sizeof(uint32_t));
|
||||
if (!mcit)
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(histogram, 0, nb_color * sizeof(uint32_t));
|
||||
for (int i = 0; i < nb_color; i++)
|
||||
{
|
||||
iot[i] = i;
|
||||
}
|
||||
memset(mcit, 0, nb_color * sizeof(uint32_t));
|
||||
|
||||
/* calculate histogram of image */
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
histogram[bitmap[i]]++;
|
||||
}
|
||||
shell_sort((void*)iot, nb_color, sizeof(*iot), check_trans_tn_intensity, (void*)&ti);
|
||||
|
||||
/* using selection sort since need to find only max_color */
|
||||
for (int i = 0; i < max_color; i++)
|
||||
{
|
||||
uint32_t max_val = 0;
|
||||
uint32_t max_ind = 0;
|
||||
int j;
|
||||
for (j = 0; j < nb_color; j++)
|
||||
{
|
||||
if (max_val < histogram[iot[j]])
|
||||
{
|
||||
max_val = histogram[iot[j]];
|
||||
max_ind = j;
|
||||
}
|
||||
}
|
||||
for (j = i; j > 0 && max_ind < mcit[j - 1]; j--)
|
||||
{
|
||||
mcit[j] = mcit[j - 1];
|
||||
}
|
||||
mcit[j] = max_ind;
|
||||
histogram[iot[max_ind]] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0, mxi = 0; i < nb_color; i++)
|
||||
{
|
||||
int step, inc;
|
||||
if (i == mcit[mxi])
|
||||
{
|
||||
mxi = (mxi < max_color) ? mxi + 1 : mxi;
|
||||
continue;
|
||||
}
|
||||
inc = (mxi) ? -1 : 0;
|
||||
step = mcit[mxi + inc] + ((mcit[mxi] - mcit[mxi + inc]) / 3);
|
||||
if (i <= step)
|
||||
{
|
||||
int index = iot[mcit[mxi + inc]];
|
||||
alpha[i] = alpha[index];
|
||||
palette[i].red = palette[index].red;
|
||||
palette[i].blue = palette[index].blue;
|
||||
palette[i].green = palette[index].green;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = iot[mcit[mxi]];
|
||||
alpha[i] = alpha[index];
|
||||
palette[i].red = palette[index].red;
|
||||
palette[i].blue = palette[index].blue;
|
||||
palette[i].green = palette[index].green;
|
||||
}
|
||||
|
||||
}
|
||||
end: freep(&histogram);
|
||||
freep(&mcit);
|
||||
freep(&iot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *context)
|
||||
{
|
||||
struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
|
||||
int x_pos, y_pos, width, height, i;
|
||||
int x, y, y_off, x_off, ret;
|
||||
int x, y, y_off, x_off, ret=0;
|
||||
uint8_t *pbuf;
|
||||
char *filename;
|
||||
struct cc_bitmap* rect;
|
||||
png_color *palette = NULL;
|
||||
png_byte *alpha = NULL;
|
||||
#ifdef ENABLE_OCR
|
||||
char*str = NULL;
|
||||
#endif
|
||||
|
||||
x_pos = -1;
|
||||
y_pos = -1;
|
||||
@@ -685,14 +551,13 @@ int write_cc_bitmap_as_spupng(struct cc_subtitle *sub, struct encoder_ctx *conte
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
/* TODO do rectangle, wise one color table should not be used for all rectangle */
|
||||
|
||||
/* TODO do rectangle wise, one color table should not be used for all rectangles */
|
||||
mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
|
||||
quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
|
||||
#ifdef ENABLE_OCR
|
||||
str = ocr_bitmap(palette,alpha,pbuf,width,height);
|
||||
if(str && str[0])
|
||||
#if ENABLE_OCR
|
||||
if (rect[0].ocr_text && *(rect[0].ocr_text))
|
||||
{
|
||||
write_spucomment(sp,str);
|
||||
write_spucomment(sp, rect[0].ocr_text);
|
||||
}
|
||||
#endif
|
||||
save_spupng(filename,pbuf,width, height, palette, alpha,rect[0].nb_colors);
|
||||
@@ -34,6 +34,4 @@ void inc_spupng_fileindex(void *ctx);
|
||||
void set_spupng_offset(void *ctx,int x,int y);
|
||||
int mapclut_paletee(png_color *palette, png_byte *alpha, uint32_t *clut,
|
||||
uint8_t depth);
|
||||
int quantize_map(png_byte *alpha, png_color *palette,
|
||||
uint8_t *bitmap, int size, int max_color, int nb_color);
|
||||
#endif
|
||||
@@ -1,32 +1,32 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2008 Alexander Chemeris
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
@@ -47,7 +47,7 @@
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#if (_MSC_VER < 1300) && defined(__cplusplus)
|
||||
extern "C++" {
|
||||
#endif
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#if (_MSC_VER < 1300) && defined(__cplusplus)
|
||||
}
|
||||
@@ -1,173 +1,174 @@
|
||||
#include "ccextractor.h"
|
||||
#include "lib_ccx.h"
|
||||
#include "ccx_common_option.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
void detect_stream_type (void)
|
||||
void detect_stream_type (struct lib_ccx_ctx *ctx)
|
||||
{
|
||||
stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
|
||||
startbytes_avail = (int) buffered_read_opt (startbytes,STARTBYTESLENGTH);
|
||||
|
||||
if( startbytes_avail == -1)
|
||||
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
|
||||
ctx->startbytes_avail = (int) buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
|
||||
|
||||
if( ctx->startbytes_avail == -1)
|
||||
fatal (EXIT_READ_ERROR, "Error reading input file!\n");
|
||||
|
||||
if (startbytes_avail>=4)
|
||||
if (ctx->startbytes_avail>=4)
|
||||
{
|
||||
// Check for ASF magic bytes
|
||||
if (startbytes[0]==0x30 &&
|
||||
startbytes[1]==0x26 &&
|
||||
startbytes[2]==0xb2 &&
|
||||
startbytes[3]==0x75)
|
||||
stream_mode=CCX_SM_ASF;
|
||||
if (ctx->startbytes[0]==0x30 &&
|
||||
ctx->startbytes[1]==0x26 &&
|
||||
ctx->startbytes[2]==0xb2 &&
|
||||
ctx->startbytes[3]==0x75)
|
||||
ctx->stream_mode=CCX_SM_ASF;
|
||||
}
|
||||
if (stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail >= 4)
|
||||
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 4)
|
||||
{
|
||||
if(startbytes[0]==0xb7 &&
|
||||
startbytes[1]==0xd8 &&
|
||||
startbytes[2]==0x00 &&
|
||||
startbytes[3]==0x20)
|
||||
stream_mode=CCX_SM_WTV;
|
||||
if(ctx->startbytes[0]==0xb7 &&
|
||||
ctx->startbytes[1]==0xd8 &&
|
||||
ctx->startbytes[2]==0x00 &&
|
||||
ctx->startbytes[3]==0x20)
|
||||
ctx->stream_mode = CCX_SM_WTV;
|
||||
}
|
||||
#ifdef WTV_DEBUG
|
||||
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail>=6)
|
||||
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=6)
|
||||
{
|
||||
// Check for hexadecimal dump generated by wtvccdump
|
||||
// ; CCHD
|
||||
if (startbytes[0]==';' &&
|
||||
startbytes[1]==' ' &&
|
||||
startbytes[2]=='C' &&
|
||||
startbytes[3]=='C' &&
|
||||
startbytes[4]=='H' &&
|
||||
startbytes[5]=='D')
|
||||
stream_mode= CCX_SM_HEX_DUMP;
|
||||
if (ctx->startbytes[0]==';' &&
|
||||
ctx->startbytes[1]==' ' &&
|
||||
ctx->startbytes[2]=='C' &&
|
||||
ctx->startbytes[3]=='C' &&
|
||||
ctx->startbytes[4]=='H' &&
|
||||
ctx->startbytes[5]=='D')
|
||||
ctx->stream_mode= CCX_SM_HEX_DUMP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && startbytes_avail>=11)
|
||||
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=11)
|
||||
{
|
||||
// Check for CCExtractor magic bytes
|
||||
if (startbytes[0]==0xCC &&
|
||||
startbytes[1]==0xCC &&
|
||||
startbytes[2]==0xED &&
|
||||
startbytes[8]==0 &&
|
||||
startbytes[9]==0 &&
|
||||
startbytes[10]==0)
|
||||
stream_mode=CCX_SM_RCWT;
|
||||
if (ctx->startbytes[0]==0xCC &&
|
||||
ctx->startbytes[1]==0xCC &&
|
||||
ctx->startbytes[2]==0xED &&
|
||||
ctx->startbytes[8]==0 &&
|
||||
ctx->startbytes[9]==0 &&
|
||||
ctx->startbytes[10]==0)
|
||||
ctx->stream_mode=CCX_SM_RCWT;
|
||||
}
|
||||
if (stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
|
||||
if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
|
||||
{
|
||||
if (startbytes_avail > 188*8) // Otherwise, assume no TS
|
||||
if (ctx->startbytes_avail > 188*8) // Otherwise, assume no TS
|
||||
{
|
||||
// First check for TS
|
||||
for (unsigned i=0; i<188;i++)
|
||||
{
|
||||
if (startbytes[i]==0x47 && startbytes[i+188]==0x47 &&
|
||||
startbytes[i+188*2]==0x47 && startbytes[i+188*3]==0x47 &&
|
||||
startbytes[i+188*4]==0x47 && startbytes[i+188*5]==0x47 &&
|
||||
startbytes[i+188*6]==0x47 && startbytes[i+188*7]==0x47
|
||||
if (ctx->startbytes[i]==0x47 && ctx->startbytes[i+188]==0x47 &&
|
||||
ctx->startbytes[i+188*2]==0x47 && ctx->startbytes[i+188*3]==0x47 &&
|
||||
ctx->startbytes[i+188*4]==0x47 && ctx->startbytes[i+188*5]==0x47 &&
|
||||
ctx->startbytes[i+188*6]==0x47 && ctx->startbytes[i+188*7]==0x47
|
||||
)
|
||||
{
|
||||
// Eight sync bytes, that's good enough
|
||||
startbytes_pos=i;
|
||||
stream_mode=CCX_SM_TRANSPORT;
|
||||
// Eight sync bytes, that's good enough
|
||||
ctx->startbytes_pos=i;
|
||||
ctx->stream_mode=CCX_SM_TRANSPORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now check for PS (Needs PACK header)
|
||||
for (unsigned i=0;
|
||||
i < (unsigned) (startbytes_avail<50000?startbytes_avail-3:49997);
|
||||
i < (unsigned) (ctx->startbytes_avail<50000?ctx->startbytes_avail-3:49997);
|
||||
i++)
|
||||
{
|
||||
if (startbytes[i]==0x00 && startbytes[i+1]==0x00 &&
|
||||
startbytes[i+2]==0x01 && startbytes[i+3]==0xBA)
|
||||
if (ctx->startbytes[i]==0x00 && ctx->startbytes[i+1]==0x00 &&
|
||||
ctx->startbytes[i+2]==0x01 && ctx->startbytes[i+3]==0xBA)
|
||||
{
|
||||
// If we find a PACK header it is not an ES
|
||||
startbytes_pos=i;
|
||||
stream_mode=CCX_SM_PROGRAM;
|
||||
ctx->startbytes_pos=i;
|
||||
ctx->stream_mode=CCX_SM_PROGRAM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TiVo is also a PS
|
||||
if (startbytes[0]=='T' && startbytes[1]=='i' &&
|
||||
startbytes[2]=='V' && startbytes[3]=='o')
|
||||
if (ctx->startbytes[0]=='T' && ctx->startbytes[1]=='i' &&
|
||||
ctx->startbytes[2]=='V' && ctx->startbytes[3]=='o')
|
||||
{
|
||||
// The TiVo header is longer, but the PS loop will find the beginning
|
||||
startbytes_pos=187;
|
||||
stream_mode=CCX_SM_PROGRAM;
|
||||
ctx->startbytes_pos=187;
|
||||
ctx->stream_mode=CCX_SM_PROGRAM;
|
||||
strangeheader=1; // Avoid message about unrecognized header
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
startbytes_pos=0;
|
||||
stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
ctx->startbytes_pos=0;
|
||||
ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
if ((stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
|
||||
&& startbytes_avail>=4) // Still not found
|
||||
if ((ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
|
||||
&& ctx->startbytes_avail>=4) // Still not found
|
||||
{
|
||||
// Try for MP4 by looking for box signatures - this should happen very
|
||||
// Try for MP4 by looking for box signatures - this should happen very
|
||||
// early in the file according to specs
|
||||
for (int i=0;i<startbytes_avail-3;i++)
|
||||
for (int i=0;i<ctx->startbytes_avail-3;i++)
|
||||
{
|
||||
// Look for the a box of type 'file'
|
||||
if (
|
||||
(startbytes[i]=='f' && startbytes[i+1]=='t' &&
|
||||
startbytes[i+2]=='y' && startbytes[i+3]=='p')
|
||||
(ctx->startbytes[i]=='f' && ctx->startbytes[i+1]=='t' &&
|
||||
ctx->startbytes[i+2]=='y' && ctx->startbytes[i+3]=='p')
|
||||
||
|
||||
(startbytes[i]=='m' && startbytes[i+1]=='o' &&
|
||||
startbytes[i+2]=='o' && startbytes[i+3]=='v')
|
||||
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='o' &&
|
||||
ctx->startbytes[i+2]=='o' && ctx->startbytes[i+3]=='v')
|
||||
||
|
||||
(startbytes[i]=='m' && startbytes[i+1]=='d' &&
|
||||
startbytes[i+2]=='a' && startbytes[i+3]=='t')
|
||||
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='d' &&
|
||||
ctx->startbytes[i+2]=='a' && ctx->startbytes[i+3]=='t')
|
||||
||
|
||||
(startbytes[i]=='f' && startbytes[i+1]=='e' &&
|
||||
startbytes[i+2]=='e' && startbytes[i+3]=='e')
|
||||
(ctx->startbytes[i]=='f' && ctx->startbytes[i+1]=='e' &&
|
||||
ctx->startbytes[i+2]=='e' && ctx->startbytes[i+3]=='e')
|
||||
||
|
||||
(startbytes[i]=='s' && startbytes[i+1]=='k' &&
|
||||
startbytes[i+2]=='i' && startbytes[i+3]=='p')
|
||||
(ctx->startbytes[i]=='s' && ctx->startbytes[i+1]=='k' &&
|
||||
ctx->startbytes[i+2]=='i' && ctx->startbytes[i+3]=='p')
|
||||
||
|
||||
(startbytes[i]=='u' && startbytes[i+1]=='d' &&
|
||||
startbytes[i+2]=='t' && startbytes[i+3]=='a')
|
||||
(ctx->startbytes[i]=='u' && ctx->startbytes[i+1]=='d' &&
|
||||
ctx->startbytes[i+2]=='t' && ctx->startbytes[i+3]=='a')
|
||||
||
|
||||
(startbytes[i]=='m' && startbytes[i+1]=='e' &&
|
||||
startbytes[i+2]=='t' && startbytes[i+3]=='a')
|
||||
(ctx->startbytes[i]=='m' && ctx->startbytes[i+1]=='e' &&
|
||||
ctx->startbytes[i+2]=='t' && ctx->startbytes[i+3]=='a')
|
||||
||
|
||||
(startbytes[i]=='v' && startbytes[i+1]=='o' &&
|
||||
startbytes[i+2]=='i' && startbytes[i+3]=='d')
|
||||
(ctx->startbytes[i]=='v' && ctx->startbytes[i+1]=='o' &&
|
||||
ctx->startbytes[i+2]=='i' && ctx->startbytes[i+3]=='d')
|
||||
)
|
||||
{
|
||||
stream_mode=CCX_SM_MP4;
|
||||
ctx->stream_mode=CCX_SM_MP4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't use STARTBYTESLENGTH. It might be longer than the file length!
|
||||
return_to_buffer (startbytes, startbytes_avail);
|
||||
return_to_buffer (ctx->startbytes, ctx->startbytes_avail);
|
||||
}
|
||||
|
||||
|
||||
int detect_myth( void )
|
||||
int detect_myth( struct lib_ccx_ctx *ctx )
|
||||
{
|
||||
int vbi_blocks=0;
|
||||
// VBI data? if yes, use myth loop
|
||||
// STARTBTYTESLENGTH is 1MB, if the file is shorter we will never detect
|
||||
// it as a mythTV file
|
||||
if (startbytes_avail==STARTBYTESLENGTH)
|
||||
if (ctx->startbytes_avail==STARTBYTESLENGTH)
|
||||
{
|
||||
unsigned char uc[3];
|
||||
memcpy (uc,startbytes,3);
|
||||
for (int i=3;i<startbytes_avail;i++)
|
||||
memcpy (uc,ctx->startbytes,3);
|
||||
for (int i=3;i<ctx->startbytes_avail;i++)
|
||||
{
|
||||
if (((uc[0]=='t') && (uc[1]=='v') && (uc[2] == '0')) ||
|
||||
((uc[0]=='T') && (uc[1]=='V') && (uc[2] == '0')))
|
||||
vbi_blocks++;
|
||||
uc[0]=uc[1];
|
||||
uc[1]=uc[2];
|
||||
uc[2]=startbytes[i];
|
||||
}
|
||||
uc[2]=ctx->startbytes[i];
|
||||
}
|
||||
}
|
||||
if (vbi_blocks>10) // Too much coincidence
|
||||
return 1;
|
||||
@@ -185,24 +186,24 @@ int read_pts_pes(unsigned char*header, int len)
|
||||
|
||||
//function used only to set start time
|
||||
if(pts_set)
|
||||
return -1;
|
||||
return -1;
|
||||
//it might not be pes packet
|
||||
if (!(header[0] == 0 && header[1] == 0 && header[2] == 1))
|
||||
return -1;
|
||||
if (!(header[0] == 0 && header[1] == 0 && header[2] == 1))
|
||||
return -1;
|
||||
|
||||
|
||||
/* peslen = header[4] << 8 | header[5]; */
|
||||
|
||||
if (header[7] & 0x80)
|
||||
{
|
||||
{
|
||||
bits_9 = ((LLONG) header[9] & 0x0E) << 29; // PTS 32..30 - Must be LLONG to prevent overflow
|
||||
bits_10 = header[10] << 22; // PTS 29..22
|
||||
bits_11 = (header[11] & 0xFE) << 14; // PTS 21..15
|
||||
bits_12 = header[12] << 7; // PTS 14-7
|
||||
bits_13 = header[13] >> 1; // PTS 6-0
|
||||
}
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return -1;
|
||||
current_pts = bits_9 | bits_10 | bits_11 | bits_12 | bits_13;
|
||||
pts_set = 1;
|
||||
|
||||
@@ -216,7 +217,7 @@ int read_pts_pes(unsigned char*header, int len)
|
||||
* 0 .. Read from file into nextheader
|
||||
* >0 .. Use data in nextheader with the length of sbuflen
|
||||
*/
|
||||
int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbuflen)
|
||||
int read_video_pes_header (struct lib_ccx_ctx *ctx, unsigned char *nextheader, int *headerlength, int sbuflen)
|
||||
{
|
||||
// Read the next video PES
|
||||
// ((nextheader[3]&0xf0)==0xe0)
|
||||
@@ -227,8 +228,8 @@ int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbu
|
||||
if ( !sbuflen )
|
||||
{
|
||||
// Extension present, get it
|
||||
buffered_read (nextheader+6,3);
|
||||
past=past+result;
|
||||
buffered_read (ctx, nextheader+6,3);
|
||||
ctx->past=ctx->past+result;
|
||||
if (result!=3) {
|
||||
// Consider this the end of the show.
|
||||
return -1;
|
||||
@@ -248,8 +249,8 @@ int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbu
|
||||
if ( !sbuflen )
|
||||
{
|
||||
if (nextheader[8] > 0) {
|
||||
buffered_read (nextheader+9,nextheader[8]);
|
||||
past=past+result;
|
||||
buffered_read (ctx, nextheader+9,nextheader[8]);
|
||||
ctx->past=ctx->past+result;
|
||||
if (result!=nextheader[8]) {
|
||||
return -1;
|
||||
}
|
||||
@@ -329,13 +330,13 @@ int read_video_pes_header (unsigned char *nextheader, int *headerlength, int sbu
|
||||
|
||||
if ( !falsepes && nextheader[7]&0x80 ) {
|
||||
// Read PTS from byte 9,10,11,12,13
|
||||
|
||||
LLONG bits_9 = ((LLONG) nextheader[9] & 0x0E)<<29; // PTS 32..30 - Must be LLONG to prevent overflow
|
||||
|
||||
LLONG bits_9 = ((LLONG) nextheader[9] & 0x0E)<<29; // PTS 32..30 - Must be LLONG to prevent overflow
|
||||
unsigned bits_10 = nextheader[10] << 22; // PTS 29..22
|
||||
unsigned bits_11 = (nextheader[11] & 0xFE) << 14; // PTS 21..15
|
||||
unsigned bits_12 = nextheader[12] << 7; // PTS 14-7
|
||||
unsigned bits_13 = nextheader[13] >> 1; // PTS 6-0
|
||||
|
||||
|
||||
if (pts_set) // Otherwise can't check for rollovers yet
|
||||
{
|
||||
if (!bits_9 && ((current_pts_33>>30)&7)==7) // PTS about to rollover
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user