1 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2012  MOGI, Kazuhiro <kazhiro@marumo.ne.jp>
3 
4  Permission to use, copy, modify, and/or distribute this software for any
5  purpose with or without fee is hereby granted, provided that the above
6  copyright notice and this permission notice appear in all copies.
7 
8  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  PERFORMANCE OF THIS SOFTWARE.
15  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <io.h>
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 
26 #include <windows.h>
27 #include <crtdbg.h>
28 
29 #include "arib_std_b25.h"
30 #include "b_cas_card.h"
31 
32 typedef struct {
33 	int32_t round;
34 	int32_t strip;
35 	int32_t emm;
36 	int32_t verbose;
37 	int32_t power_ctrl;
38 } OPTION;
39 
40 static void show_usage();
41 static int parse_arg(OPTION *dst, int argc, char **argv);
42 static void test_arib_std_b25(const char *src, const char *dst, OPTION *opt);
43 static void show_bcas_power_on_control_info(B_CAS_CARD *bcas);
44 
main(int argc,char ** argv)45 int main(int argc, char **argv)
46 {
47 	int n;
48 	OPTION opt;
49 
50 	#if defined(WIN32)
51 	_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
52 	_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
53 	_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
54 	_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
55 	_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
56 	_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
57 	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_DELAY_FREE_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF);
58 	#endif
59 
60 	n = parse_arg(&opt, argc, argv);
61 	if(n+2 > argc){
62 		show_usage();
63 		exit(EXIT_FAILURE);
64 	}
65 
66 	for(;n<=(argc-2);n+=2){
67 		test_arib_std_b25(argv[n+0], argv[n+1], &opt);
68 	}
69 
70 	#if defined(WIN32)
71 	_CrtDumpMemoryLeaks();
72 	#endif
73 
74 	return EXIT_SUCCESS;
75 }
76 
show_usage()77 static void show_usage()
78 {
79 	fprintf(stderr, "b25 - ARIB STD-B25 test program ver. 0.2.5 (2012, 2/13)\n");
80 	fprintf(stderr, "usage: b25 [options] src.m2t dst.m2t [more pair ..]\n");
81 	fprintf(stderr, "options:\n");
82 	fprintf(stderr, "  -r round (integer, default=4)\n");
83 	fprintf(stderr, "  -s strip\n");
84 	fprintf(stderr, "     0: keep null(padding) stream (default)\n");
85 	fprintf(stderr, "     1: strip null stream\n");
86 	fprintf(stderr, "  -m EMM\n");
87 	fprintf(stderr, "     0: ignore EMM (default)\n");
88 	fprintf(stderr, "     1: send EMM to B-CAS card\n");
89 	fprintf(stderr, "  -p power_on_control_info\n");
90 	fprintf(stderr, "     0: do nothing additionaly\n");
91 	fprintf(stderr, "     1: show B-CAS EMM receiving request (default)\n");
92 	fprintf(stderr, "  -v verbose\n");
93 	fprintf(stderr, "     0: silent\n");
94 	fprintf(stderr, "     1: show processing status (default)\n");
95 	fprintf(stderr, "\n");
96 }
97 
parse_arg(OPTION * dst,int argc,char ** argv)98 static int parse_arg(OPTION *dst, int argc, char **argv)
99 {
100 	int i;
101 
102 	dst->round = 4;
103 	dst->strip = 0;
104 	dst->emm = 0;
105 	dst->power_ctrl = 1;
106 	dst->verbose = 1;
107 
108 	for(i=1;i<argc;i++){
109 		if(argv[i][0] != '-'){
110 			break;
111 		}
112 		switch(argv[i][1]){
113 		case 'm':
114 			if(argv[i][2]){
115 				dst->emm = atoi(argv[i]+2);
116 			}else{
117 				dst->emm = atoi(argv[i+1]);
118 				i += 1;
119 			}
120 			break;
121 		case 'p':
122 			if(argv[i][2]){
123 				dst->power_ctrl = atoi(argv[i]+2);
124 			}else{
125 				dst->power_ctrl = atoi(argv[i+1]);
126 				i += 1;
127 			}
128 			break;
129 		case 'r':
130 			if(argv[i][2]){
131 				dst->round = atoi(argv[i]+2);
132 			}else{
133 				dst->round = atoi(argv[i+1]);
134 				i += 1;
135 			}
136 			break;
137 		case 's':
138 			if(argv[i][2]){
139 				dst->strip = atoi(argv[i]+2);
140 			}else{
141 				dst->strip = atoi(argv[i+1]);
142 				i += 1;
143 			}
144 			break;
145 		case 'v':
146 			if(argv[i][2]){
147 				dst->verbose = atoi(argv[i]+2);
148 			}else{
149 				dst->verbose = atoi(argv[i+1]);
150 				i += 1;
151 			}
152 			break;
153 		default:
154 			fprintf(stderr, "error - unknown option '-%c'\n", argv[i][1]);
155 			return argc;
156 		}
157 	}
158 
159 	return i;
160 }
161 
test_arib_std_b25(const char * src,const char * dst,OPTION * opt)162 static void test_arib_std_b25(const char *src, const char *dst, OPTION *opt)
163 {
164 	int code,i,n,m;
165 	int sfd,dfd;
166 
167 	int64_t total;
168 	int64_t offset;
169 #if defined(WIN32)
170 	unsigned long tick,tock;
171 #else
172 	struct timeval tick,tock;
173 	double millisec;
174 #endif
175 	double mbps;
176 
177 	ARIB_STD_B25 *b25;
178 	B_CAS_CARD   *bcas;
179 
180 	ARIB_STD_B25_PROGRAM_INFO pgrm;
181 
182 	uint8_t data[64*1024];
183 
184 	ARIB_STD_B25_BUFFER sbuf;
185 	ARIB_STD_B25_BUFFER dbuf;
186 
187 	sfd = -1;
188 	dfd = -1;
189 	b25 = NULL;
190 	bcas = NULL;
191 
192 	sfd = _open(src, _O_BINARY|_O_RDONLY|_O_SEQUENTIAL);
193 	if(sfd < 0){
194 		fprintf(stderr, "error - failed on _open(%s) [src]\n", src);
195 		goto LAST;
196 	}
197 
198 	_lseeki64(sfd, 0, SEEK_END);
199 	total = _telli64(sfd);
200 	_lseeki64(sfd, 0, SEEK_SET);
201 
202 	b25 = create_arib_std_b25();
203 	if(b25 == NULL){
204 		fprintf(stderr, "error - failed on create_arib_std_b25()\n");
205 		goto LAST;
206 	}
207 
208 	code = b25->set_multi2_round(b25, opt->round);
209 	if(code < 0){
210 		fprintf(stderr, "error - failed on ARIB_STD_B25::set_multi2_round() : code=%d\n", code);
211 		goto LAST;
212 	}
213 
214 	code = b25->set_strip(b25, opt->strip);
215 	if(code < 0){
216 		fprintf(stderr, "error - failed on ARIB_STD_B25::set_strip() : code=%d\n", code);
217 		goto LAST;
218 	}
219 
220 	code = b25->set_emm_proc(b25, opt->emm);
221 	if(code < 0){
222 		fprintf(stderr, "error - failed on ARIB_STD_B25::set_emm_proc() : code=%d\n", code);
223 		goto LAST;
224 	}
225 
226 	bcas = create_b_cas_card();
227 	if(bcas == NULL){
228 		fprintf(stderr, "error - failed on create_b_cas_card()\n");
229 		goto LAST;
230 	}
231 
232 	code = bcas->init(bcas);
233 	if(code < 0){
234 		fprintf(stderr, "error - failed on B_CAS_CARD::init() : code=%d\n", code);
235 		goto LAST;
236 	}
237 
238 	code = b25->set_b_cas_card(b25, bcas);
239 	if(code < 0){
240 		fprintf(stderr, "error - failed on ARIB_STD_B25::set_b_cas_card() : code=%d\n", code);
241 		goto LAST;
242 	}
243 
244 	dfd = _open(dst, _O_BINARY|_O_WRONLY|_O_SEQUENTIAL|_O_CREAT|_O_TRUNC, _S_IREAD|_S_IWRITE);
245 	if(dfd < 0){
246 		fprintf(stderr, "error - failed on _open(%s) [dst]\n", dst);
247 		goto LAST;
248 	}
249 
250 	offset = 0;
251 #if defined(WIN32)
252 	tock = GetTickCount();
253 #else
254 	gettimeofday(&tock, NULL);
255 #endif
256 	while( (n = _read(sfd, data, sizeof(data))) > 0 ){
257 		sbuf.data = data;
258 		sbuf.size = n;
259 
260 		code = b25->put(b25, &sbuf);
261 		if(code < 0){
262 			fprintf(stderr, "error - failed on ARIB_STD_B25::put() : code=%d\n", code);
263 			goto LAST;
264 		}
265 
266 		code = b25->get(b25, &dbuf);
267 		if(code < 0){
268 			fprintf(stderr, "error - failed on ARIB_STD_B25::get() : code=%d\n", code);
269 			goto LAST;
270 		}
271 
272 		if(dbuf.size > 0){
273 			n = _write(dfd, dbuf.data, dbuf.size);
274 			if(n != dbuf.size){
275 				fprintf(stderr, "error failed on _write(%d)\n", dbuf.size);
276 				goto LAST;
277 			}
278 		}
279 
280 		offset += sbuf.size;
281 		if(opt->verbose != 0){
282 			m = (int)(10000*offset/total);
283 			mbps = 0.0;
284 #if defined(WIN32)
285 			tick = GetTickCount();
286 			if (tick-tock > 100) {
287 				mbps = offset;
288 				mbps /= 1024;
289 				mbps /= (tick-tock);
290 			}
291 #else
292 			gettimeofday(&tick, NULL);
293 			millisec = (tick.tv_sec - tock.tv_sec) * 1000;
294 			millisec += (tick.tv_usec - tock.tv_usec) / 1000;
295 			if(millisec > 100.0) {
296 				mbps = offset;
297 				mbps /= 1024;
298 				mbps /= millisec;
299 			}
300 #endif
301 			fprintf(stderr, "\rprocessing: %2d.%02d%% [%6.2f MB/sec]", m/100, m%100, mbps);
302 		}
303 	}
304 
305 	code = b25->flush(b25);
306 	if(code < 0){
307 		fprintf(stderr, "error - failed on ARIB_STD_B25::flush() : code=%d\n", code);
308 		goto LAST;
309 	}
310 
311 	code = b25->get(b25, &dbuf);
312 	if(code < 0){
313 		fprintf(stderr, "error - failed on ARIB_STD_B25::get() : code=%d\n", code);
314 		goto LAST;
315 	}
316 
317 	if(dbuf.size > 0){
318 		n = _write(dfd, dbuf.data, dbuf.size);
319 		if(n != dbuf.size){
320 			fprintf(stderr, "error - failed on _write(%d)\n", dbuf.size);
321 			goto LAST;
322 		}
323 	}
324 
325 	if(opt->verbose != 0){
326 		mbps = 0.0;
327 #if defined(WIN32)
328 		tick = GetTickCount();
329 		if (tick-tock > 100) {
330 			mbps = offset;
331 			mbps /= 1024;
332 			mbps /= (tick-tock);
333 		}
334 #else
335 		gettimeofday(&tick, NULL);
336 		millisec = (tick.tv_sec - tock.tv_sec) * 1000;
337 		millisec += (tick.tv_usec - tock.tv_usec) / 1000;
338 		if(millisec > 100.0) {
339 			mbps = offset;
340 			mbps /= 1024;
341 			mbps /= millisec;
342 		}
343 #endif
344 		fprintf(stderr, "\rprocessing: finish  [%6.2f MB/sec]\n", mbps);
345 		fflush(stderr);
346 		fflush(stdout);
347 	}
348 
349 	n = b25->get_program_count(b25);
350 	if(n < 0){
351 		fprintf(stderr, "error - failed on ARIB_STD_B25::get_program_count() : code=%d\n", code);
352 		goto LAST;
353 	}
354 	for(i=0;i<n;i++){
355 		code = b25->get_program_info(b25, &pgrm, i);
356 		if(code < 0){
357 			fprintf(stderr, "error - failed on ARIB_STD_B25::get_program_info(%d) : code=%d\n", i, code);
358 			goto LAST;
359 		}
360 		if(pgrm.ecm_unpurchased_count > 0){
361 			fprintf(stderr, "warning - unpurchased ECM is detected\n");
362 			fprintf(stderr, "  channel:               %d\n", pgrm.program_number);
363 			fprintf(stderr, "  unpurchased ECM count: %d\n", pgrm.ecm_unpurchased_count);
364 			fprintf(stderr, "  last ECM error code:   %04x\n", pgrm.last_ecm_error_code);
365 			#if defined(WIN32)
366 			fprintf(stderr, "  undecrypted TS packet: %d\n", pgrm.undecrypted_packet_count);
367 			fprintf(stderr, "  total TS packet:       %d\n", pgrm.total_packet_count);
368 			#else
369 			fprintf(stderr, "  undecrypted TS packet: %"PRId64"\n", pgrm.undecrypted_packet_count);
370 			fprintf(stderr, "  total TS packet:       %"PRId64"\n", pgrm.total_packet_count);
371 			#endif
372 		}
373 	}
374 
375 	if(opt->power_ctrl != 0){
376 		show_bcas_power_on_control_info(bcas);
377 	}
378 
379 LAST:
380 
381 	if(sfd >= 0){
382 		_close(sfd);
383 		sfd = -1;
384 	}
385 
386 	if(dfd >= 0){
387 		_close(dfd);
388 		dfd = -1;
389 	}
390 
391 	if(b25 != NULL){
392 		b25->release(b25);
393 		b25 = NULL;
394 	}
395 
396 	if(bcas != NULL){
397 		bcas->release(bcas);
398 		bcas = NULL;
399 	}
400 }
401 
show_bcas_power_on_control_info(B_CAS_CARD * bcas)402 static void show_bcas_power_on_control_info(B_CAS_CARD *bcas)
403 {
404 	int code;
405 	int i,w;
406 	B_CAS_PWR_ON_CTRL_INFO pwc;
407 
408 	code = bcas->get_pwr_on_ctrl(bcas, &pwc);
409 	if(code < 0){
410 		fprintf(stderr, "error - failed on B_CAS_CARD::get_pwr_on_ctrl() : code=%d\n", code);
411 		return;
412 	}
413 
414 	if(pwc.count == 0){
415 		fprintf(stdout, "no EMM receiving request\n");
416 		return;
417 	}
418 
419 	fprintf(stdout, "total %d EMM receiving request\n", pwc.count);
420 	for(i=0;i<pwc.count;i++){
421 		fprintf(stdout, "+ [%d] : tune ", i);
422 		switch(pwc.data[i].network_id){
423 		case 4:
424 			w = pwc.data[i].transport_id;
425 			fprintf(stdout, "BS-%d/TS-%d ", ((w >> 4) & 0x1f), (w & 7));
426 			break;
427 		case 6:
428 		case 7:
429 			w = pwc.data[i].transport_id;
430 			fprintf(stdout, "ND-%d/TS-%d ", ((w >> 4) & 0x1f), (w & 7));
431 			break;
432 		default:
433 			fprintf(stdout, "unknown(b:0x%02x,n:0x%04x,t:0x%04x) ", pwc.data[i].broadcaster_group_id, pwc.data[i].network_id, pwc.data[i].transport_id);
434 			break;
435 		}
436 		fprintf(stdout, "between %04d %02d/%02d ", pwc.data[i].s_yy, pwc.data[i].s_mm, pwc.data[i].s_dd);
437 		fprintf(stdout, "to %04d %02d/%02d ", pwc.data[i].l_yy, pwc.data[i].l_mm, pwc.data[i].l_dd);
438 		fprintf(stdout, "least %d hours\n", pwc.data[i].hold_time);
439 	}
440 }
441 
442