Mercurial > pt1.oyama
comparison recpt1/tssplitter_lite.c @ 96:52f8e081763d
add an option to specify the necessary service IDs.
patch by Naoya OYAMA <naoya.oyama@gmail.com>, based on the code of tssplitter_lite by querulous.
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Wed, 10 Feb 2010 14:33:32 +0900 |
parents | |
children | 3fd15032fd3a |
comparison
equal
deleted
inserted
replaced
95:a201531113ca | 96:52f8e081763d |
---|---|
1 /* tssplitter_lite.c -- split TS stream. | |
2 | |
3 Copyright 2009 querulous | |
4 Copyright 2010 Naoya OYAMA <naoya.oyama@gmail.com> | |
5 | |
6 This program is free software: you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation, either version 3 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
18 | |
19 #include <stdlib.h> | |
20 #include <stdio.h> | |
21 #include <string.h> | |
22 #include <ctype.h> | |
23 | |
24 #include <fcntl.h> | |
25 #include <sys/stat.h> | |
26 #include "decoder.h" | |
27 #include "recpt1.h" | |
28 #include "tssplitter_lite.h" | |
29 | |
30 | |
31 /** | |
32 * サービスID解析 | |
33 */ | |
34 char** AnalyzeSid( | |
35 char* sid) // [in] サービスID(カンマ区切りテキスト) | |
36 { | |
37 int i = 0; | |
38 char** sid_list = NULL; | |
39 char* p; | |
40 int CommaNum = 0; | |
41 | |
42 /* sid は次の形式の引数を許容する */ | |
43 /* 指定無し */ | |
44 /* SID[0] */ | |
45 /* SID[0],SID[1],...,SID[N-1],SID[N] */ | |
46 | |
47 /*カンマの数を数える*/ | |
48 p = sid; | |
49 while(*p != '\0') | |
50 { | |
51 if( *p == C_CHAR_COMMA ){ | |
52 CommaNum++; | |
53 } | |
54 p++; | |
55 } | |
56 | |
57 /* sid_listの数はカンマの数+2(NULL止めするから) */ | |
58 sid_list = malloc(sizeof(char*)*(CommaNum+2)); | |
59 if ( sid_list == NULL ) | |
60 { | |
61 fprintf(stderr, "AnalyzeSid() malloc error.\n"); | |
62 return NULL; | |
63 } | |
64 | |
65 /* sidが空である場合 */ | |
66 p = sid; | |
67 if ( strlen(p) == 0 ) | |
68 { | |
69 sid_list[0] = NULL; | |
70 return sid_list; | |
71 } | |
72 | |
73 /* カンマ無し */ | |
74 if ( CommaNum == 0 ) | |
75 { | |
76 sid_list[0] = sid; | |
77 sid_list[1] = NULL; | |
78 return sid_list; | |
79 } | |
80 | |
81 /* カンマ区切りで複数指定時 */ | |
82 i=0; | |
83 p = sid; | |
84 /* 文字列端に到達するか、カンマ数が数えた数に達したら終了 */ | |
85 while((*p != '\0') || i < CommaNum) | |
86 { | |
87 /* 現在の処理位置をsid_list[i]にセット */ | |
88 /* このタイミングの p は | |
89 * ・sid先頭 | |
90 * ・[,]の次の文字 | |
91 * いずれかであるので p を sid_list[i] に代入してよい | |
92 */ | |
93 sid_list[i] = p; | |
94 i++; | |
95 | |
96 /* 最初に現れる[,]をNULL文字で置換する */ | |
97 p = strchr(p, C_CHAR_COMMA); | |
98 if ( p == NULL ) | |
99 { | |
100 /* カンマが見つからない場合は最後の処理対象なので終了 */ | |
101 break; | |
102 } | |
103 *p = '\0'; | |
104 /* 処理位置をNULLで置換した文字の次の位置に設定する */ | |
105 p++; | |
106 } | |
107 | |
108 /* 最後のsid_list[n]はNULLポインタで止める */ | |
109 sid_list[i] = NULL; | |
110 | |
111 i=0; | |
112 while( sid_list[i] != NULL ) | |
113 { | |
114 i++; | |
115 } | |
116 for(i=0; sid_list[i] != NULL; i++) | |
117 { | |
118 printf("sid_list[%d]=[%s].\n",i, sid_list[i]); | |
119 } | |
120 return sid_list; | |
121 } | |
122 | |
123 /** | |
124 * 初期化処理 | |
125 */ | |
126 splitter* split_startup( | |
127 char *sid // [in] サービスID(引数で指定した文字列) | |
128 ) | |
129 { | |
130 splitter* sp; | |
131 sp = malloc(sizeof(splitter)); | |
132 if ( sp == NULL ) | |
133 { | |
134 fprintf(stderr, "split_startup malloc error.\n"); | |
135 return NULL; | |
136 } | |
137 memset(sp->pids, 0, sizeof(sp->pids)); | |
138 memset(sp->pmt_pids, 0, sizeof(sp->pmt_pids)); | |
139 | |
140 sp->sid_list = NULL; | |
141 sp->pat = NULL; | |
142 sp->sid_list = AnalyzeSid(sid); | |
143 if ( sp->sid_list == NULL ) | |
144 { | |
145 free(sp); | |
146 return NULL; | |
147 } | |
148 sp->pat_count = 0xFF; | |
149 sp->pmt_drop = -1; | |
150 sp->pmt_counter = 0; | |
151 | |
152 return sp; | |
153 } | |
154 | |
155 /** | |
156 * 落とすPIDを確定させる | |
157 */ | |
158 int split_select( | |
159 splitter *sp, // [in/out] splitter構造体 | |
160 ARIB_STD_B25_BUFFER *sbuf // [in] 入力TS | |
161 ) | |
162 { | |
163 int result; | |
164 // TS解析 | |
165 result = ReadTs(&(sp->pat), sp->pids, sp->sid_list, sp->pmt_pids, sbuf, &(sp->pmt_drop), &(sp->pmt_counter)); | |
166 | |
167 return result; | |
168 } | |
169 | |
170 /** | |
171 * 終了処理 | |
172 */ | |
173 void split_shutdown( | |
174 splitter* sp | |
175 ) | |
176 { | |
177 if ( sp != NULL ) { | |
178 if ( sp->pat != NULL ) | |
179 { | |
180 free(sp->pat); | |
181 sp->pat = NULL; | |
182 } | |
183 if ( sp->sid_list != NULL ) | |
184 { | |
185 free(sp->sid_list); | |
186 sp->sid_list = NULL; | |
187 } | |
188 free(sp); | |
189 sp = NULL; | |
190 } | |
191 } | |
192 | |
193 /** | |
194 * TS 解析処理 | |
195 * | |
196 * 対象のチャンネル番号のみの PAT の再構築と出力対象 PID の抽出を行う | |
197 */ | |
198 int ReadTs( | |
199 unsigned char** pat, // [out] PAT 情報(再構築後) | |
200 unsigned char* pids, // [out] 出力対象 PID 情報 | |
201 char** sid_list, // [in] 出力対象サービス ID のリスト | |
202 unsigned char* pmt_pids, // [in] 出力対象PIDのPMT PID | |
203 ARIB_STD_B25_BUFFER *sbuf, // [in] pt1_drvの入力TS | |
204 int* pmt_drop, // [in] PMTの落とすべき数 | |
205 int* pmt_counter // [out] PMTの落とした数 | |
206 ) | |
207 { | |
208 int length = sbuf->size; | |
209 int pid; | |
210 int result = TSS_ERROR; | |
211 int index; | |
212 | |
213 index = 0; | |
214 while (((length - index - LENGTH_PACKET)) > 0) | |
215 { | |
216 pid = GetPid(((unsigned char*)sbuf->data)+index+1); | |
217 // PAT | |
218 if (0x0000 == pid) | |
219 { | |
220 result = AnalyzePat(((unsigned char*)sbuf->data)+index, pat, pids, sid_list, pmt_pids, pmt_drop); | |
221 if (TSS_SUCCESS != result) | |
222 { | |
223 /* 下位の関数内部でmalloc error発生 */ | |
224 return result; | |
225 } | |
226 } | |
227 | |
228 // PMT | |
229 /* 落とすpmt_pidである場合には、pmtに書かれている | |
230 * 落とすべきPCR/AUDIO/VIDEO PIDを取得する */ | |
231 if (pmt_pids[pid] == 1) | |
232 { | |
233 /* この中にはPMT毎に一度しか入らないようにしておく */ | |
234 AnalyzePmt(((unsigned char*)sbuf->data)+index, pids); | |
235 pmt_pids[pid]++; | |
236 *pmt_counter = *(pmt_counter)+1; | |
237 } | |
238 /* 全ての落とすPMTの中に書かれている、落とすPCR/AUDIO/VIDEOのPIDを得たら処理を抜ける */ | |
239 /* pmt_counter と pmt_drop が一致する場合に条件は満たされる */ | |
240 if ((*pmt_counter == *pmt_drop)) { | |
241 result = TSS_SUCCESS; | |
242 break; | |
243 } | |
244 else | |
245 { | |
246 result = TSS_ERROR; | |
247 } | |
248 index += LENGTH_PACKET; | |
249 } | |
250 | |
251 return(result); | |
252 } | |
253 | |
254 /** | |
255 * TS 分離処理 | |
256 */ | |
257 int split_ts( | |
258 splitter *splitter, // [in] splitterパラメータ | |
259 ARIB_STD_B25_BUFFER *sbuf, // [in] 入力TS | |
260 BUFSZ *dbuf // [out] 出力TS | |
261 ) | |
262 { | |
263 int pid; | |
264 int s_offset = 0; | |
265 int d_offset = 0; | |
266 | |
267 /* 初期化 */ | |
268 dbuf->size = 0; | |
269 if ( sbuf->size < 0 ) | |
270 { | |
271 return TSS_ERROR; | |
272 } | |
273 | |
274 while (sbuf->size > s_offset) | |
275 { | |
276 pid = GetPid(((unsigned char*)sbuf->data)+s_offset+1); | |
277 | |
278 // PAT | |
279 if (0x0000 == pid) | |
280 { | |
281 // 巡回カウンタカウントアップ | |
282 if (0xFF == splitter->pat_count) | |
283 { | |
284 splitter->pat_count = splitter->pat[3]; | |
285 } else | |
286 { | |
287 splitter->pat_count = (splitter->pat_count)+1; | |
288 if (0 == splitter->pat_count % 0x10) | |
289 { | |
290 splitter->pat_count = splitter->pat_count - 0x10; | |
291 } | |
292 } | |
293 splitter->pat[3] = splitter->pat_count; | |
294 | |
295 memcpy(((unsigned char*)dbuf->buffer)+d_offset, splitter->pat, LENGTH_PACKET); | |
296 d_offset += LENGTH_PACKET; | |
297 dbuf->size = dbuf->size + LENGTH_PACKET; | |
298 } | |
299 | |
300 // その他 PID | |
301 else | |
302 { | |
303 /* pids[pid] が 0 は落とさないパケットなので書き込む */ | |
304 if (0 == splitter->pids[pid]) | |
305 { | |
306 memcpy(((unsigned char*)dbuf->buffer)+d_offset, ((unsigned char*)sbuf->data)+s_offset, LENGTH_PACKET); | |
307 d_offset += LENGTH_PACKET; | |
308 dbuf->size = dbuf->size + LENGTH_PACKET; | |
309 } | |
310 } | |
311 s_offset = s_offset + LENGTH_PACKET; | |
312 } | |
313 | |
314 return(TSS_SUCCESS); | |
315 } | |
316 | |
317 /** | |
318 * PAT 解析処理 | |
319 * | |
320 * PAT を解析し、出力対象チャンネルが含まれているかチェックを行い、PAT を再構築する | |
321 */ | |
322 int AnalyzePat( | |
323 unsigned char* buf, // [in] 読み込んだバッファ | |
324 unsigned char** pat, // [out] PAT 情報(再構築後) | |
325 unsigned char* pids, // [out] 出力対象 PID 情報 | |
326 char** sid_list, // [in] 出力対象サービス ID のリスト | |
327 unsigned char* pmt_pids, // [out] サービス ID に対応する PMT の PID | |
328 int* pmt_drop) // [out] 落とすPMTの数 | |
329 { | |
330 int pos[MAX_PID]; | |
331 int service_id; | |
332 int i; | |
333 int size = 0; | |
334 int pid; | |
335 int result = TSS_SUCCESS; | |
336 char **p; | |
337 int sid_found; | |
338 | |
339 if (NULL == *pat) | |
340 { | |
341 /* 初期化 */ | |
342 *pmt_drop = 0; | |
343 memset(pos, 0, sizeof(pos)); | |
344 size = buf[7]; | |
345 | |
346 // 対象チャンネル判定 | |
347 /* size + 8 = パケット全長 */ | |
348 /* 最終 4 バイトはCRCなので飛ばす */ | |
349 for (i = 17; i < (size + 8) - 4; i = i + 4) | |
350 { | |
351 sid_found = 0; | |
352 service_id = (buf[i] << 8) + buf[i + 1]; | |
353 p = sid_list; | |
354 while(*p != NULL) | |
355 { | |
356 if (service_id == atoi(*p)) | |
357 { | |
358 /* 録画対象 = 落とす対象とはしないものなので、基本的に何もしない */ | |
359 /* 録画対象の pmt_pids は 0 とする */ | |
360 /* 録画対象の pmt の pids は 0 とする */ | |
361 pid = GetPid(&buf[i + 2]); | |
362 *(pmt_pids+pid) = 0; | |
363 *(pids+pid) = 0; | |
364 pos[pid] = i; | |
365 sid_found = 1; | |
366 break; | |
367 } | |
368 else if (strstr(*p, "all") != NULL ) | |
369 { | |
370 /* all指定時には全保存する */ | |
371 pid = GetPid(&buf[i + 2]); | |
372 *(pmt_pids+pid) = 0; | |
373 *(pids+pid) = 0; | |
374 pos[pid] = i; | |
375 sid_found = 1; | |
376 break; | |
377 } | |
378 p++; | |
379 } | |
380 if ( ! sid_found ) | |
381 { | |
382 /* sid_list を全部なめたが録画対象であると判定されないものを落とす */ | |
383 /* 削除対象の pmt_pids は 1 とする */ | |
384 /* 削除対象の pmt の pids は 1 とする */ | |
385 pid = GetPid(&buf[i + 2]); | |
386 *(pmt_pids+pid) = 1; | |
387 *(pids+pid) = 1; | |
388 pos[pid] = i; | |
389 *(pmt_drop) = *(pmt_drop)+1; | |
390 } | |
391 } | |
392 // PAT 再構築 | |
393 result = RecreatePat(buf, pat, pids, pos); | |
394 } | |
395 | |
396 return(result); | |
397 } | |
398 | |
399 /** | |
400 * PAT 再構築処理 | |
401 * | |
402 * PMT から出力対象チャンネル以外のチャンネル情報を削除し、PAT を再構築する | |
403 */ | |
404 int RecreatePat( | |
405 unsigned char* buf, // [in] 読み込んだバッファ | |
406 unsigned char** pat, // [out] PAT 情報(再構築後) | |
407 unsigned char* pids, // [out] 出力対象 PID 情報 | |
408 int *pos) // [in] 取得対象 PMT のバッファ中の位置 | |
409 { | |
410 unsigned char y[LENGTH_CRC_DATA]; | |
411 int crc; | |
412 int i; | |
413 int j; | |
414 int pos_i; | |
415 int pid_num = 0; | |
416 | |
417 // CRC 計算のためのデータ | |
418 { | |
419 // チャンネルによって変わらない部分 | |
420 for (i = 0; i < LENGTH_PAT_HEADER; i++) | |
421 { | |
422 y[i] = buf[i + 5]; | |
423 } | |
424 // チャンネルによって変わる部分 | |
425 for (i = 0; i < MAX_PID; i++) | |
426 { | |
427 if(pos[i] != 0) | |
428 { | |
429 /* buf[pos_i] を y にコピー(抽出したPIDの数) */ | |
430 pos_i = pos[i]; | |
431 for (j = 0; j < 4; j++) | |
432 { | |
433 y[LENGTH_PAT_HEADER + ((4*pid_num) + j)] = buf[pos_i + j]; | |
434 } | |
435 pid_num++; | |
436 } | |
437 } | |
438 } | |
439 /* パケットサイズ計算 */ | |
440 y[2] = pid_num * 4 + 0x0d; | |
441 // CRC 計算 | |
442 crc = GetCrc32(y, LENGTH_PAT_HEADER + pid_num*4); | |
443 | |
444 // PAT 再構成 | |
445 *pat = (unsigned char*)malloc(LENGTH_PACKET); | |
446 if ( *pat == NULL ) | |
447 { | |
448 fprintf(stderr, "RecreatePat() malloc error.\n"); | |
449 return(TSS_NULL); | |
450 } | |
451 memset(*pat, 0xFF, LENGTH_PACKET); | |
452 for (i = 0; i < 5; i++) | |
453 { | |
454 (*pat)[i] = buf[i]; | |
455 } | |
456 for (i = 0; i < LENGTH_PAT_HEADER + pid_num*4; i++) | |
457 { | |
458 (*pat)[i + 5] = y[i]; | |
459 } | |
460 (*pat)[5 + LENGTH_PAT_HEADER + pid_num*4] = (crc >> 24) & 0xFF; | |
461 (*pat)[6 + LENGTH_PAT_HEADER + pid_num*4] = (crc >> 16) & 0xFF; | |
462 (*pat)[7 + LENGTH_PAT_HEADER + pid_num*4] = (crc >> 8) & 0xFF; | |
463 (*pat)[8 + LENGTH_PAT_HEADER + pid_num*4] = (crc ) & 0xFF; | |
464 return(TSS_SUCCESS); | |
465 } | |
466 | |
467 /** | |
468 * PMT 解析処理 | |
469 * | |
470 * PMT を解析し、削除対象の PID を特定する | |
471 */ | |
472 int AnalyzePmt( | |
473 unsigned char* buf, // [in] 読み込んだバッファ | |
474 unsigned char* pids) // [out] 出力対象 PID 情報 | |
475 { | |
476 unsigned char Nall; | |
477 unsigned char N; | |
478 int pcr; | |
479 int epid; | |
480 | |
481 Nall = ((buf[6] & 0x0F) << 4) + buf[7]; | |
482 | |
483 // PCR | |
484 pcr = GetPid(&buf[13]); | |
485 pids[pcr] = 1; | |
486 | |
487 N = ((buf[15] & 0x0F) << 4) + buf[16] + 16 + 1; | |
488 | |
489 // ES PID | |
490 while (N < Nall + 8 - 4) | |
491 { | |
492 epid = GetPid(&buf[N + 1]); | |
493 | |
494 pids[epid] = 1; | |
495 N += 4 + (((buf[N + 3]) & 0x0F) << 4) + buf[N + 4] + 1; | |
496 } | |
497 | |
498 return TSS_SUCCESS; | |
499 } | |
500 | |
501 /** | |
502 * CRC 計算 | |
503 */ | |
504 int GetCrc32( | |
505 unsigned char* data, // [in] CRC 計算対象データ | |
506 int len) // [in] CRC 計算対象データ長 | |
507 { | |
508 int crc; | |
509 int i, j; | |
510 int c; | |
511 int bit; | |
512 | |
513 crc = 0xFFFFFFFF; | |
514 for (i = 0; i < len; i++) | |
515 { | |
516 char x; | |
517 x = data[i]; | |
518 | |
519 for (j = 0; j < 8; j++) | |
520 { | |
521 | |
522 bit = (x >> (7 - j)) & 0x1; | |
523 | |
524 c = 0; | |
525 if (crc & 0x80000000) | |
526 { | |
527 c = 1; | |
528 } | |
529 | |
530 crc = crc << 1; | |
531 | |
532 if (c ^ bit) | |
533 { | |
534 crc ^= 0x04C11DB7; | |
535 } | |
536 | |
537 crc &= 0xFFFFFFFF; | |
538 } | |
539 } | |
540 | |
541 return crc; | |
542 } | |
543 | |
544 /** | |
545 * PID 取得 | |
546 */ | |
547 int GetPid( | |
548 unsigned char* data) // [in] 取得対象データのポインタ | |
549 { | |
550 return ((data[0] & 0x1F) << 8) + data[1]; | |
551 } |