3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
16 * This product includes software developed by Hidetoshi Shimokawa.
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $FreeBSD: src/usr.sbin/fwcontrol/fwdv.c$
36 #include <sys/param.h>
38 #include <sys/ioctl.h>
41 #include <sys/types.h>
44 #if __FreeBSD_version >= 500000 || defined(__HAIKU__)
45 #include <arpa/inet.h>
64 #include <dev/firewire/firewire.h>
65 #include <dev/firewire/iec68113.h>
68 #include "fwmethods.h"
77 struct frac frame_cycle
[2] = {
78 {8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */
79 {320, 1}, /* PAL 8000 cycle / 25 Hz */
85 struct frac pad_rate
[2] = {
86 {203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */
87 {1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */
89 char *system_name
[] = {"NTSC", "PAL"};
90 int frame_rate
[] = {30, 25};
98 #define TNBUF 100 /* XXX too large value causes block noise */
99 #define NEMPTY 10 /* depends on TNBUF */
100 #define RBUFSIZE (PSIZE * NPACKET_R)
101 #define MAXBLOCKS (300)
102 #define CYCLE_FRAC 0xc00
105 dvrecv(int d
, const char *filename
, char ich
, int count
)
107 struct fw_isochreq isoreq
;
108 struct fw_isobufreq bufreq
;
114 int len
, tlen
, npad
, fd
, k
, m
, vec
, system
= -1, nb
;
115 int nblocks
[] = {250 /* NTSC */, 300 /* PAL */};
116 struct iovec wbuf
[NPACKET_R
];
118 if(strcmp(filename
, "-") == 0) {
121 fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0660);
123 err(EX_NOINPUT
, "%s", filename
);
125 buf
= malloc(RBUFSIZE
);
126 pad
= malloc(DSIZE
*MAXBLOCKS
);
127 memset(pad
, 0xff, DSIZE
*MAXBLOCKS
);
128 bzero(wbuf
, sizeof(wbuf
));
130 bufreq
.rx
.nchunk
= NCHUNK
;
131 bufreq
.rx
.npacket
= NPACKET_R
;
132 bufreq
.rx
.psize
= PSIZE
;
133 bufreq
.tx
.nchunk
= 0;
134 bufreq
.tx
.npacket
= 0;
136 if (ioctl(d
, FW_SSTBUF
, &bufreq
) < 0)
137 err(1, "ioctl FW_SSTBUF");
139 isoreq
.ch
= ich
& 0x3f;
140 isoreq
.tag
= (ich
>> 6) & 3;
142 if (ioctl(d
, FW_SRSTREAM
, &isoreq
) < 0)
146 while (count
<= 0 || k
<= count
) {
149 while ((len
= read(d
, buf
+ tlen
, PSIZE
150 /* RBUFSIZE - tlen */)) > 0) {
152 if (errno
== EAGAIN
) {
153 fprintf(stderr
, "(EAGAIN)\n");
158 err(1, "read failed");
161 if ((RBUFSIZE
- tlen
) < PSIZE
)
165 tlen
= len
= read(d
, buf
, RBUFSIZE
);
167 if (errno
== EAGAIN
) {
168 fprintf(stderr
, "(EAGAIN) - push 'Play'?\n");
173 err(1, "read failed");
177 ptr
= (u_int32_t
*) buf
;
179 pkt
= (struct fw_pkt
*) ptr
;
181 fprintf(stderr
, "%08x %08x %08x %08x\n",
182 htonl(ptr
[0]), htonl(ptr
[1]),
183 htonl(ptr
[2]), htonl(ptr
[3]));
185 ciph
= (struct ciphdr
*)(ptr
+ 1); /* skip iso header */
186 if (ciph
->fmt
!= CIP_FMT_DVCR
)
187 errx(1, "unknown format 0x%x", ciph
->fmt
);
188 ptr
= (u_int32_t
*) (ciph
+ 1); /* skip cip header */
190 if (ciph
->fdf
.dv
.cyc
!= 0xffff && k
== 0) {
191 fprintf(stderr
, "0x%04x\n", ntohs(ciph
->fdf
.dv
.cyc
));
194 if (pkt
->mode
.stream
.len
<= sizeof(struct ciphdr
))
197 for (dv
= (struct dvdbc
*)ptr
;
198 (char *)dv
< (char *)(ptr
+ ciph
->len
);
202 fprintf(stderr
, "(%d,%d) ", dv
->sct
, dv
->dseq
);
204 if (dv
->sct
== DV_SCT_HEADER
&& dv
->dseq
== 0) {
206 system
= ciph
->fdf
.dv
.fs
;
207 fprintf(stderr
, "%s\n", system_name
[system
]);
212 (dv
->payload
[0] & DV_DSF_12
) == 0)
213 dv
->payload
[0] |= DV_DSF_12
;
214 nb
= nblocks
[system
];
215 fprintf(stderr
, "%d:%02d:%02d %d\r",
216 k
/ (3600 * frame_rate
[system
]),
217 (k
/ (60 * frame_rate
[system
])) % 60,
218 (k
/ frame_rate
[system
]) % 60,
219 k
% frame_rate
[system
]);
222 if (m
> 0 && m
!= nb
) {
223 /* padding bad frame */
224 npad
= ((nb
- m
) % nb
);
227 fprintf(stderr
, "\n%d blocks padded\n",
230 wbuf
[vec
].iov_base
= pad
;
231 wbuf
[vec
++].iov_len
= npad
;
232 if (vec
>= NPACKET_R
) {
233 writev(fd
, wbuf
, vec
);
242 if (k
== 0 || (count
> 0 && k
> count
))
245 wbuf
[vec
].iov_base
= (char *) dv
;
246 wbuf
[vec
++].iov_len
= DSIZE
;
247 if (vec
>= NPACKET_R
) {
248 writev(fd
, wbuf
, vec
);
252 ptr
= (u_int32_t
*)dv
;
254 if ((char *)ptr
< buf
+ tlen
)
257 writev(fd
, wbuf
, vec
);
259 if (fd
!= STDOUT_FILENO
)
261 fprintf(stderr
, "\n");
266 dvsend(int d
, const char *filename
, char ich
, int count
)
268 struct fw_isochreq isoreq
;
269 struct fw_isobufreq bufreq
;
272 int len
, tlen
, header
, fd
, frames
, packets
, vec
, offset
, nhdr
, i
;
273 int system
=-1, pad_acc
, cycle_acc
, cycle
, f_cycle
, f_frac
;
274 struct iovec wbuf
[TNBUF
*2 + NEMPTY
];
276 u_int32_t iso_data
, iso_empty
, hdr
[TNBUF
+ NEMPTY
][3];
278 struct timeval start
, end
;
281 fd
= open(filename
, O_RDONLY
);
283 err(EX_NOINPUT
, "%s", filename
);
285 pbuf
= malloc(DSIZE
* TNBUF
);
286 bzero(wbuf
, sizeof(wbuf
));
288 bufreq
.rx
.nchunk
= 0;
289 bufreq
.rx
.npacket
= 0;
291 bufreq
.tx
.nchunk
= NCHUNK
;
292 bufreq
.tx
.npacket
= NPACKET_T
;
293 bufreq
.tx
.psize
= PSIZE
;
294 if (ioctl(d
, FW_SSTBUF
, &bufreq
) < 0)
295 err(1, "ioctl FW_SSTBUF");
297 isoreq
.ch
= ich
& 0x3f;
298 isoreq
.tag
= (ich
>> 6) & 3;
300 if (ioctl(d
, FW_STSTREAM
, &isoreq
) < 0)
301 err(1, "ioctl FW_STSTREAM");
304 pkt
= (struct fw_pkt
*) &iso_data
;
305 pkt
->mode
.stream
.len
= DSIZE
+ sizeof(struct ciphdr
);
306 pkt
->mode
.stream
.sy
= 0;
307 pkt
->mode
.stream
.tcode
= FWTCODE_STREAM
;
308 pkt
->mode
.stream
.chtag
= ich
;
309 iso_empty
= iso_data
;
310 pkt
= (struct fw_pkt
*) &iso_empty
;
311 pkt
->mode
.stream
.len
= sizeof(struct ciphdr
);
313 bzero(hdr
[0], sizeof(hdr
[0]));
314 hdr
[0][0] = iso_data
;
315 ciph
= (struct ciphdr
*)&hdr
[0][1];
316 ciph
->src
= 0; /* XXX */
320 ciph
->fdf
.dv
.cyc
= 0xffff;
322 for (i
= 1; i
< TNBUF
; i
++)
323 bcopy(hdr
[0], hdr
[i
], sizeof(hdr
[0]));
325 gettimeofday(&start
, NULL
);
327 fprintf(stderr
, "%08x %08x %08x\n",
328 htonl(hdr
[0]), htonl(hdr
[1]), htonl(hdr
[2]));
335 while (tlen
< DSIZE
* TNBUF
) {
336 len
= read(fd
, pbuf
+ tlen
, DSIZE
* TNBUF
- tlen
);
343 fprintf(stderr
, "\nend of file\n");
352 dv
= (struct dvdbc
*)(pbuf
+ offset
* DSIZE
);
354 header
= (dv
->sct
== 0 && dv
->dseq
== 0);
356 header
= (packets
== 0 || packets
% npackets
[system
] == 0);
359 ciph
= (struct ciphdr
*)&hdr
[nhdr
][1];
362 system
= ((dv
->payload
[0] & DV_DSF_12
) != 0);
363 printf("%s\n", system_name
[system
]);
365 cycle_acc
= frame_cycle
[system
].d
* cycle
;
367 fprintf(stderr
, "%d", frames
% 10);
369 if (count
> 0 && frames
> count
)
371 if (frames
% frame_rate
[system
] == 0)
372 fprintf(stderr
, "\n");
374 f_cycle
= (cycle_acc
/ frame_cycle
[system
].d
) & 0xf;
375 f_frac
= (cycle_acc
% frame_cycle
[system
].d
376 * CYCLE_FRAC
) / frame_cycle
[system
].d
;
378 ciph
->fdf
.dv
.cyc
= htons(f_cycle
<< 12 | f_frac
);
380 ciph
->fdf
.dv
.cyc
= htons(cycle
<< 12 | f_frac
);
382 cycle_acc
+= frame_cycle
[system
].n
;
383 cycle_acc
%= frame_cycle
[system
].d
* 0x10;
386 ciph
->fdf
.dv
.cyc
= 0xffff;
388 ciph
->dbc
= packets
++ % 256;
389 pad_acc
+= pad_rate
[system
].n
;
390 if (pad_acc
>= pad_rate
[system
].d
) {
391 pad_acc
-= pad_rate
[system
].d
;
392 bcopy(hdr
[nhdr
], hdr
[nhdr
+1], sizeof(hdr
[0]));
393 hdr
[nhdr
][0] = iso_empty
;
394 wbuf
[vec
].iov_base
= (char *)hdr
[nhdr
];
395 wbuf
[vec
++].iov_len
= sizeof(hdr
[0]);
399 hdr
[nhdr
][0] = iso_data
;
400 wbuf
[vec
].iov_base
= (char *)hdr
[nhdr
];
401 wbuf
[vec
++].iov_len
= sizeof(hdr
[0]);
402 wbuf
[vec
].iov_base
= (char *)dv
;
403 wbuf
[vec
++].iov_len
= DSIZE
;
407 if (offset
* DSIZE
< tlen
)
411 len
= writev(d
, wbuf
, vec
);
413 if (errno
== EAGAIN
) {
414 fprintf(stderr
, "(EAGAIN) - push 'Play'?\n");
417 err(1, "write failed");
421 fprintf(stderr
, "\n");
423 gettimeofday(&end
, NULL
);
424 rtime
= end
.tv_sec
- start
.tv_sec
425 + (end
.tv_usec
- start
.tv_usec
) * 1e-6;
426 fprintf(stderr
, "%d frames, %.2f secs, %.2f frames/sec\n",
427 frames
, rtime
, frames
/rtime
);