libclosedcaption 1.0.3
Extração de closed caption ISDB-Tb/SBTVD de arquivos MPEG-TS
Carregando...
Procurando...
Nenhuma entrada encontrado
libclosedcaption

🇺🇸 English · 🇧🇷 Português (pt_BR)

CI Release [License: LGPL v3](LICENSE) Docs

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

  1. Compile o exemplo:

    make example
  2. 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
  3. 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_line (const CaptionLine_t *line, void *userdata)
{
printf ("[%u ms] %s\n", line->start_ms, line->text);
}
static void on_pes (const uint8_t *pes, size_t len, void *userdata)
{
caption_screen_push_pes (userdata, pes, len);
}
TsReader_t *reader = ts_reader_open ("video.ts", NULL);
TsDemux_t *demux = ts_demux_new ();
CaptionScreen_t *screen = caption_screen_new (on_line, NULL);
const uint8_t *packet;
ts_demux_set_pes_callback (demux, 0x3ed, on_pes, screen);
while ((packet = ts_reader_next (reader)) != NULL)
ts_demux_push (demux, 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.
const char * text
uint32_t start_ms
void ts_demux_flush(TsDemux_t *demux)
struct TsDemux_s TsDemux_t
Definição ts-demux.h:82
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
Definição ts-reader.h:57
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:

make docs

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.