🇺🇸 English · 🇧🇷 Português (pt_BR)
[
](LICENSE) 
Biblioteca em C para extrair o closed caption (legenda oculta) do padrão ISDB-Tb/SBTVD (ARIB STD-B24 / ABNT NBR 15606-1) a partir dos pacotes PES de legenda de um MPEG-TS.
Ela foi usada, e ainda está em uso, em várias TVs vendidas no Brasil que seguem o padrão brasileiro de TV digital (DTV ISDB-Tb).
A biblioteca não faz o demux do TS: ela recebe o PES da legenda e entrega o texto (em UTF-8) e os comandos de controle através de callbacks. O example/main.c mostra como fazer o demux e usar a API.
Instalando
make
sudo make install # PREFIX=/usr/local por padrão (DESTDIR e PREFIX funcionam)
Instala a .so (com soname libclosedcaption.so.1), a .a, os headers em $PREFIX/include/closedcaption (use #include <closedcaption/caption.h>) e o libclosedcaption.pc, então dá pra compilar assim:
cc meu-programa.c $(pkg-config --cflags --libs libclosedcaption)
Tem também a imagem de container no GitHub Packages: docker run --rm -v "$PWD:/d" ghcr.io/jpereira/libclosedcaption /d/video.ts.
Versão em runtime com closedcaption_version() (e CLOSEDCAPTION_VERSION_* no header).
Estrutura
include/closedcaption/ headers da biblioteca (caption.h inclui todos)
src/ implementação
example/ exemplo de uso: lê um .ts e imprime as legendas
docs/ amostra de TS com legenda (veja docs/pt_BR/README.md)
Compilando
make # gera libclosedcaption.so
make example # gera example/example
make run-example # roda o exemplo com a amostra de docs/
make clean
No macOS o Makefile passa o SDK (xcrun --show-sdk-path) para o compilador, então funciona também com compiladores fora do Xcode, como o LLVM do Homebrew.
Rodando o exemplo
Compile o exemplo:
Rode sem informar o PID para listar os PIDs do arquivo. O PID da legenda é identificado pela PMT e marcado com <- legenda:
./example/example docs/tv-camara-isdbtb-legenda.ts
PIDs encontrados em 'docs/tv-camara-isdbtb-legenda.ts':
PID Pacotes Programa Tipo
0x0000 153 - PAT
...
0x03e8 34 16512 PMT
0x03ea 200 16512 0x1b H.264 video (component_tag 0x00)
0x03eb 1353 16512 0x11 AAC LATM audio (component_tag 0x10)
0x03ed 120 16512 0x06 PES privado (component_tag 0x30, legenda) <- legenda
...
Para exibir as legendas:
./example/example docs/tv-camara-isdbtb-legenda.ts 0x03ed
Rode novamente passando o PID para exibir as legendas:
./example/example docs/tv-camara-isdbtb-legenda.ts 0x03ed
[00:00:00.000] QUE RESISTAM AO
[00:00:00.066] DESENTENDIMENTO ENTRE OS
[00:00:02.102] PREFEITOS, NO CASO
[00:00:03.370] ESPECÍFICO AQUI
[00:00:03.870] METROPOLITANO. SE NÓS
[00:00:04.637] DIZEMOS QUE A SOLUÇÃO É
[00:00:06.172] ENTRAR NUMA MESA E CHEGAR
[00:00:07.173] NO ACORDO, NÓS NÃO
[00:00:08.341] PRECISAMOS DE LEI PARA
[00:00:09.309] ISSO, ELES JÁ PODEM FAZER
10 linha(s) de legenda extraída(s) do PID 0x03ed.
Para ver também as data units de DRCS, bitmap, geométrico, som e superimpose, use --units:
./example/example tests/sintetico-unidades.ts 0x130 --units
O tempo é relativo à primeira legenda. As legendas são impressas no stdout e as mensagens no stderr, então > legendas.txt grava apenas o texto.
O exemplo aceita pacotes de 188 bytes (TS), 192 (M2TS) e 204 (TS com Reed-Solomon, comum em capturas de ISDB-T).
Usando a API
{
}
static void on_pes (const uint8_t *pes, size_t len, void *userdata)
{
}
const uint8_t *packet;
bool caption_screen_push_pes(CaptionScreen_t *screen, const uint8_t *pes, size_t len)
CaptionScreen_t * caption_screen_new(CaptionScreenLineCallback_t callback, void *userdata)
void caption_screen_flush(CaptionScreen_t *screen)
struct CaptionScreen_s CaptionScreen_t
Header principal: inclui todos os módulos da biblioteca.
void ts_demux_flush(TsDemux_t *demux)
struct TsDemux_s TsDemux_t
void ts_demux_set_pes_callback(TsDemux_t *demux, uint16_t pid, TsDemuxPesCallback_t callback, void *userdata)
TsDemux_t * ts_demux_new(void)
void ts_demux_push(TsDemux_t *demux, const uint8_t *packet)
const uint8_t * ts_reader_next(TsReader_t *reader)
struct TsReader_s TsReader_t
TsReader_t * ts_reader_open(const char *filename, TsReaderError_t *error)
Quem já tem o próprio demux pode usar só o caption_screen_push_pes(), ou as funções de baixo nível com os hooks de caption-hooking.h. A documentação completa é gerada com make docs e publicada em https://jpereira.github.io/libclosedcaption/pt_BR/.
Documentação
Instale o Doxygen e o Graphviz e execute:
Abra build/docs/html/pt_BR/index.html (ou build/docs/html/index.html, em inglês) para consultar o site localmente, com o guia de uso e a referência da API.
O site fica em https://jpereira.github.io/libclosedcaption/pt_BR/.
Testes
make test # compara o exemplo com a amostra real e os TS sintéticos + testes da API
make test-sanitize # mesma coisa com ASan + UBSan
make lint # cppcheck
make fuzz # libFuzzer (clang): build/fuzz-pes -max_total_time=60
O CI roda isso tudo em Linux (gcc/clang) e macOS a cada push. Veja o CONTRIBUTING.
Limitações
- Apenas texto em ISO-8859-15 (legendas brasileiras); legendas japonesas não são suportadas.
- O texto do superimpose e as data units de DRCS (1 e 2 bytes), bitmap, gráficos geométricos e som são lidos, mas a lib não desenha nem toca nada: ela entrega os dados para a aplicação. A data unit de mapa de cores ainda é um esqueleto.
- Os parsers de DRCS, bitmap, geométrico e som só foram testados com streams sintéticos (
tests/sintetico-unidades.ts), as capturas reais que achei não têm essas data units.
- Do "caption management data" só o primeiro idioma é lido.
Releases
Versão no arquivo VERSION (SemVer), histórico no CHANGELOG. O ./bump.sh fecha a versão atual (commit + tag) e abre a próxima; a tag dispara a release com tarball e a imagem de container.
Licença
LGPL-3.0, veja o [LICENSE](LICENSE). Achou bug de segurança? Veja o SECURITY.