libclosedcaption 1.0.3
ISDB-Tb/SBTVD (Brazilian DTV) closed caption extraction from MPEG-TS
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
16
18static void
19on_line (const CaptionLine_t *line,
20 void *userdata)
21{
22 unsigned *count = userdata;
23 uint32_t ms = line->start_ms;
24
25 printf ("[%02u:%02u:%02u.%03u] %s\n",
26 ms / 3600000, (ms / 60000) % 60, (ms / 1000) % 60, ms % 1000, line->text);
27
28 (*count)++;
29}
30
32typedef struct {
33 CaptionScreen_t *screen;
34 bool units;
35} Context_t;
36
38static void
39drcs_print (const CaptionSuperImpose1ByteDrcs_t *d)
40{
41 for (; d != NULL; d = d->next)
42 {
43 unsigned x, y;
44
45 printf (" codigo=0x%04x fonte=%u modo=%u", d->character_code, d->font_id, d->mode);
46
48 {
49 printf (" geometrico=%u byte(s) regiao=%ux%u\n", d->geometric_len, d->region_x, d->region_y);
50 continue;
51 }
52
53 printf (" %ux%u gradacoes=%u\n", d->width, d->height, d->depth + 2);
54
55 for (y = 0; d->pixels != NULL && y < d->height; y++)
56 {
57 printf (" ");
58 for (x = 0; x < d->width; x++)
59 {
60 uint8_t v = d->pixels[y * d->width + x];
61
62 putchar (v == 0 ? '.' : (v < 10 ? '0' + v : 'a' + v - 10));
63 }
64 putchar ('\n');
65 }
66 }
67}
68
70static void
71unit_print (const CaptionManagement_t *m)
72{
74 {
77 {
81
82 printf ("[unidade] DRCS de %d byte(s)%s\n", one ? 1 : 2, d == NULL ? ": invalido" : "");
83 drcs_print (d);
85 break;
86 }
87
89 {
91
92 if (b == NULL)
93 printf ("[unidade] bitmap: invalido\n");
94 else
95 printf ("[unidade] bitmap: x=%d y=%d PNG %ux%u (%zu bytes) cores piscando=%u\n",
96 b->x, b->y, b->width, b->height, b->png_len, b->num_flc_colors);
97
99 break;
100 }
101
103 {
105
106 printf ("[unidade] geometrico%s\n", g == NULL ? ": sem comandos" : "");
107
108 for (i = g; i != NULL; i = i->next)
109 printf (" %-12s opcode=0x%02x operandos=%zu\n",
110 caption_superimpose_geometric_get_name (i->opcode), i->opcode, i->operands_len);
111
113 break;
114 }
115
117 {
119
120 printf ("[unidade] som sintetizado: %zu byte(s)\n", s == NULL ? 0 : s->len);
122 break;
123 }
124
125 default:
126 break;
127 }
128}
129
131static void
132units_print (const uint8_t *raw,
133 size_t len)
134{
135 PacketPES_t pes;
136 CaptionData_t data;
138 CaptionSuperImpose_t *msgs, *i;
139 unsigned n;
140
141 memset (&pes, 0, sizeof (pes));
142
143 if (!packet_pes_load (raw, len, &pes) || !caption_data_load (&pes, &data))
144 return;
145
146 for (n = 0; caption_management_load_unit (&data, n, &m); n++)
147 unit_print (&m);
148
149 msgs = caption_superimpose_new (&data);
150
151 for (i = msgs; i != NULL; i = i->next)
152 printf ("[superimpose] %s\n", i->text_utf8);
153
155}
156
158static void
159on_pes (const uint8_t *pes,
160 size_t len,
161 void *userdata)
162{
163 Context_t *ctx = userdata;
164
165 if (ctx->units)
166 units_print (pes, len);
167
168 caption_screen_push_pes (ctx->screen, pes, len);
169}
170
172static void
173pids_list (const TsDemux_t *demux,
174 const char *filename)
175{
176 uint16_t caption_pid = ts_demux_get_caption_pid (demux);
177 unsigned pid;
178
179 printf ("PIDs encontrados em '%s':\n", filename);
180 printf (" %-6s %8s %-8s %s\n", "PID", "Pacotes", "Programa", "Tipo");
181
182 for (pid = 0; pid < TS_PID_MAX; pid++)
183 {
184 const TsPidInfo_t *info = ts_demux_get_pid_info (demux, pid);
185 char program[16] = "-";
186 char desc[160];
187
188 if (info->packets == 0)
189 continue;
190
191 if (info->program != 0)
192 snprintf (program, sizeof (program), "%u", info->program);
193
194 printf (" 0x%04x %8u %-8s %s%s\n", pid, info->packets, program,
195 ts_demux_describe_pid (demux, pid, desc, sizeof (desc)),
196 (pid == caption_pid) ? " <- legenda" : "");
197 }
198}
199
201static bool
202parse_pid (const char *arg,
203 uint16_t *pid)
204{
205 char *end;
206 unsigned long value = strtoul (arg, &end, 0);
207
208 if (*arg == '\0' || *end != '\0' || value >= TS_PID_MAX)
209 return FALSE;
210
211 *pid = (uint16_t)value;
212 return TRUE;
213}
214
223int
224main (int argc,
225 char *argv[])
226{
227 TsReaderError_t error;
228 TsReader_t *reader;
229 TsDemux_t *demux;
230 CaptionScreen_t *screen = NULL;
231 Context_t ctx = { NULL, FALSE };
232 const uint8_t *packet;
233 uint16_t pid = TS_PID_NONE;
234 unsigned lines = 0;
235 int ret = EXIT_SUCCESS;
236
237 if (argc == 4 && strcmp (argv[3], "--units") == 0)
238 {
239 ctx.units = TRUE;
240 argc--;
241 }
242
243 if (argc < 2 || argc > 3 || (ctx.units && argc != 3))
244 {
245 fprintf (stderr, "Uso: %s <arquivo.ts> [pid da legenda [--units]]\n"
246 " Sem o [pid], lista os PIDs encontrados no arquivo.\n"
247 " Com --units, mostra tambem as data units de DRCS, bitmap, geometrico,\n"
248 " som e as mensagens de superimpose.\n", argv[0]);
249 return EXIT_FAILURE;
250 }
251
252 if (argc == 3 && !parse_pid (argv[2], &pid))
253 {
254 fprintf (stderr, "PID inválido: '%s' (use decimal ou hexadecimal, ex: 0x3ed)\n", argv[2]);
255 return EXIT_FAILURE;
256 }
257
258 reader = ts_reader_open (argv[1], &error);
259 if (reader == NULL)
260 {
261 if (error == TS_READER_ERROR_OPEN)
262 fprintf (stderr, "Erro ao abrir '%s': %s\n", argv[1], strerror (errno));
263 else if (error == TS_READER_ERROR_FORMAT)
264 fprintf (stderr, "'%s' não parece ser um MPEG-TS válido.\n", argv[1]);
265 else
266 fprintf (stderr, "Memória insuficiente.\n");
267 return EXIT_FAILURE;
268 }
269
270 demux = ts_demux_new ();
271 if (demux == NULL)
272 {
273 fprintf (stderr, "Memória insuficiente.\n");
274 ts_reader_close (reader);
275 return EXIT_FAILURE;
276 }
277
278 if (pid != TS_PID_NONE)
279 {
280 screen = caption_screen_new (on_line, &lines);
281 if (screen == NULL)
282 {
283 fprintf (stderr, "Memória insuficiente.\n");
284 ts_demux_free (demux);
285 ts_reader_close (reader);
286 return EXIT_FAILURE;
287 }
288
289 ctx.screen = screen;
290 ts_demux_set_pes_callback (demux, pid, on_pes, &ctx);
291 }
292
293 while ((packet = ts_reader_next (reader)) != NULL)
294 ts_demux_push (demux, packet);
295
296 ts_reader_close (reader);
297
298 if (screen == NULL)
299 {
300 // No PID: just lists the PIDs.
301 pids_list (demux, argv[1]);
302
304 {
305 printf ("\nNenhum PID de legenda encontrado na PMT.\n");
306 ret = EXIT_FAILURE;
307 }
308 else
309 {
310 printf ("\nPara exibir as legendas:\n %s %s 0x%04x\n",
311 argv[0], argv[1], ts_demux_get_caption_pid (demux));
312 }
313 }
314 else
315 {
316 ts_demux_flush (demux);
317 caption_screen_flush (screen);
318 fflush (stdout);
319
320 if (ts_demux_get_pid_info (demux, pid)->packets == 0)
321 {
322 fprintf (stderr, "O PID 0x%04x não existe em '%s'.\n", pid, argv[1]);
323 ret = EXIT_FAILURE;
324 }
325 else if (lines == 0)
326 {
327 fprintf (stderr, "Nenhuma legenda encontrada no PID 0x%04x.\n", pid);
328 ret = EXIT_FAILURE;
329 }
330 else
331 {
332 fprintf (stderr, "\n%u linha(s) de legenda extraída(s) do PID 0x%04x.\n", lines, pid);
333 }
334
335 caption_screen_free (screen);
336 }
337
338 ts_demux_free (demux);
339
340 return ret;
341}
#define TRUE
#define FALSE
bool caption_data_load(const PacketPES_t *pes, CaptionData_t *caption)
CaptionManagementType_t caption_management_get_type(const CaptionManagement_t *management)
@ CAPTION_HANDLER_TYPE_BITMAP
@ CAPTION_HANDLER_TYPE_1BYTE_DRCS
@ CAPTION_HANDLER_TYPE_2BYTE_DRCS
@ CAPTION_HANDLER_TYPE_SYNTHESIZED_SOUND
@ CAPTION_HANDLER_TYPE_GEOMETRIC
bool caption_management_load_unit(const CaptionData_t *caption, unsigned index, CaptionManagement_t *mgmt)
void caption_screen_free(CaptionScreen_t *screen)
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
CaptionSuperImpose1ByteDrcs_t * caption_superimpose_1bytedrcs_new(const CaptionManagement_t *m)
#define CAPTION_DRCS_MODE_MULTI_GRAD
void caption_superimpose_1bytedrcs_free(CaptionSuperImpose1ByteDrcs_t *cc)
CaptionSuperImpose2ByteDrcs_t * caption_superimpose_2bytedrcs_new(const CaptionManagement_t *m)
void caption_superimpose_bitmap_free(CaptionSuperImposeBitmap_t *cc)
CaptionSuperImposeBitmap_t * caption_superimpose_bitmap_new(const CaptionManagement_t *m)
void caption_superimpose_geometric_free(CaptionSuperImposeGeometric_t *cc)
CaptionSuperImposeGeometric_t * caption_superimpose_geometric_new(const CaptionManagement_t *m)
const char * caption_superimpose_geometric_get_name(uint8_t opcode)
void caption_superimpose_sound_free(CaptionSuperImposeSound_t *cc)
CaptionSuperImposeSound_t * caption_superimpose_sound_new(const CaptionManagement_t *m)
CaptionSuperImpose_t * caption_superimpose_new(const CaptionData_t *caption)
void caption_superimpose_free(CaptionSuperImpose_t *csi)
Main header: includes all the modules of the library.
int main(int argc, char *argv[])
Definition main.c:224
bool packet_pes_load(const uint8_t *pack_raw, const size_t raw_len, PacketPES_t *out)
const char * text
uint32_t start_ms
struct CaptionSuperImpose1ByteDrcs_t * next
CaptionSuperImpose_t * next
uint32_t packets
Definition ts-demux.h:57
uint16_t program
Definition ts-demux.h:58
const TsPidInfo_t * ts_demux_get_pid_info(const TsDemux_t *demux, uint16_t pid)
#define TS_PID_MAX
Definition ts-demux.h:48
void ts_demux_free(TsDemux_t *demux)
const char * ts_demux_describe_pid(const TsDemux_t *demux, uint16_t pid, char *buf, size_t len)
void ts_demux_flush(TsDemux_t *demux)
struct TsDemux_s TsDemux_t
Definition ts-demux.h:82
void ts_demux_set_pes_callback(TsDemux_t *demux, uint16_t pid, TsDemuxPesCallback_t callback, void *userdata)
uint16_t ts_demux_get_caption_pid(const TsDemux_t *demux)
TsDemux_t * ts_demux_new(void)
void ts_demux_push(TsDemux_t *demux, const uint8_t *packet)
#define TS_PID_NONE
Definition ts-demux.h:51
const uint8_t * ts_reader_next(TsReader_t *reader)
struct TsReader_s TsReader_t
Definition ts-reader.h:57
TsReaderError_t
Definition ts-reader.h:47
@ TS_READER_ERROR_OPEN
Definition ts-reader.h:49
@ TS_READER_ERROR_FORMAT
Definition ts-reader.h:50
void ts_reader_close(TsReader_t *reader)
TsReader_t * ts_reader_open(const char *filename, TsReaderError_t *error)