2 * FireWire DV media addon for Haiku
4 * Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
5 * Distributed under the terms of the MIT License.
10 * Hidetoshi Shimokawa. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
23 * This product includes software developed by Hidetoshi Shimokawa.
25 * 4. Neither the name of the author nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 #include "FireWireCard.h"
49 #include <sys/ioctl.h>
66 struct frac frame_cycle
[2] = {
67 {8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */
68 {320, 1}, /* PAL 8000 cycle / 25 Hz */
74 struct frac pad_rate
[2] = {
75 {203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */
76 {1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */
78 const char *system_name
[] = {"NTSC", "PAL"};
79 int frame_rate
[] = {30, 25};
85 #define DV_NPACKET_R 256
86 #define DV_NPACKET_T 255
87 #define DV_TNBUF 100 /* XXX too large value causes block noise */
88 #define DV_NEMPTY 10 /* depends on DV_TNBUF */
89 #define DV_RBUFSIZE (DV_PSIZE * DV_NPACKET_R)
90 #define DV_MAXBLOCKS (300)
91 #define DV_CYCLE_FRAC 0xc00
93 /* for MPEGTS format */
94 typedef uint8_t mpeg_ts_pld
[188];
97 #if BYTE_ORDER == BIG_ENDIAN
101 #else /* BYTE_ORDER != BIG_ENDIAN */
102 uint32_t c_offset
:12,
105 #endif /* BYTE_ORDER == BIG_ENDIAN */
110 #define MPEG_NCHUNK 8
111 #define MPEG_PSIZE 596
112 #define MPEG_NPACKET_R 4096
113 #define MPEG_RBUFSIZE (MPEG_PSIZE * MPEG_NPACKET_R)
116 FireWireCard::FireWireCard(const char* path
)
122 printf("FireWireCard opening %s\n", path
);
124 fDev
= open(path
, O_RDWR
);
126 printf("FireWireCard opening %s failed\n", path
);
127 fInitStatus
= B_ERROR
;
133 FireWireCard::~FireWireCard()
141 FireWireCard::InitCheck()
148 FireWireCard::Read(void** data
)
150 if (fFormat
== FMT_MPEGTS
)
151 return MpegtsRead(data
);
158 FireWireCard::Extract(void* dest
, void** src
, ssize_t
* sizeUsed
)
160 if (fFormat
== FMT_MPEGTS
)
161 return MpegtsExtract(dest
, src
, sizeUsed
);
163 return DvExtract(dest
, src
, sizeUsed
);
168 FireWireCard::GetBufInfo(size_t* rbufsize
, int* rcount
)
170 *rbufsize
= fRbufSize
;
176 FireWireCard::DetectRecvFn()
179 char ich
= TAG
| CHANNEL
;
180 struct fw_isochreq isoreq
;
181 struct fw_isobufreq bufreq
;
186 bufreq
.rx
.nchunk
= 8;
187 bufreq
.rx
.npacket
= 16;
188 bufreq
.rx
.psize
= 1024;
189 bufreq
.tx
.nchunk
= 0;
190 bufreq
.tx
.npacket
= 0;
193 if (ioctl(fDev
, FW_SSTBUF
, &bufreq
) < 0)
196 isoreq
.ch
= ich
& 0x3f;
197 isoreq
.tag
= (ich
>> 6) & 3;
199 if (ioctl(fDev
, FW_SRSTREAM
, &isoreq
) < 0)
202 buf
= (char*)malloc(1024*16);
203 len
= read(fDev
, buf
, 1024*16);
208 ptr
= (u_int32_t
*) buf
;
209 ciph
= (struct ciphdr
*)(ptr
+ 1);
213 fprintf(stderr
, "Detected DV format on input.\n");
215 fBuf
= malloc(DV_RBUFSIZE
);
216 fRbufSize
= DV_PSIZE
;
217 fRcount
= DV_NPACKET_R
;
218 fPad
= malloc(DV_DSIZE
*DV_MAXBLOCKS
);
219 memset(fPad
, 0xff, DV_DSIZE
*DV_MAXBLOCKS
);
222 fprintf(stderr
, "Detected MPEG TS format on input.\n");
223 fFormat
= FMT_MPEGTS
;
224 fBuf
= malloc(MPEG_RBUFSIZE
);
225 fRbufSize
= MPEG_PSIZE
;
226 fRcount
= MPEG_NPACKET_R
;
229 fprintf(stderr
, "Unsupported format for receiving: fmt=0x%x", ciph
->fmt
);
237 FireWireCard::DvRead(void** buffer
)
239 struct fw_isochreq isoreq
;
240 struct fw_isobufreq bufreq
;
242 char ich
= TAG
|CHANNEL
;
244 bufreq
.rx
.nchunk
= DV_NCHUNK
;
245 bufreq
.rx
.npacket
= DV_NPACKET_R
;
246 bufreq
.rx
.psize
= DV_PSIZE
;
247 bufreq
.tx
.nchunk
= 0;
248 bufreq
.tx
.npacket
= 0;
250 if (ioctl(fDev
, FW_SSTBUF
, &bufreq
) < 0)
253 isoreq
.ch
= ich
& 0x3f;
254 isoreq
.tag
= (ich
>> 6) & 3;
256 if (ioctl(fDev
, FW_SRSTREAM
, &isoreq
) < 0)
259 len
= read(fDev
, fBuf
, DV_RBUFSIZE
);
261 if (errno
== EAGAIN
) {
262 fprintf(stderr
, "(EAGAIN) - push 'Play'?\n");
265 fprintf(stderr
, "read failed");
274 FireWireCard::DvExtract(void* dest
, void** src
, ssize_t
* sizeUsed
)
280 int nblocks
[] = {250 /* NTSC */, 300 /* PAL */};
281 int npad
, k
, m
, system
= -1, nb
;
284 ptr
= (u_int32_t
*) (*src
);
286 pkt
= (struct fw_pkt
*) ptr
;
287 ciph
= (struct ciphdr
*)(ptr
+ 1); /* skip iso header */
288 if (ciph
->fmt
!= CIP_FMT_DVCR
) {
289 fprintf(stderr
, "unknown format 0x%x", ciph
->fmt
);
292 ptr
= (u_int32_t
*) (ciph
+ 1); /* skip cip header */
293 if (pkt
->mode
.stream
.len
<= sizeof(struct ciphdr
))
296 for (dv
= (struct dvdbc
*)ptr
;
297 (char*)dv
< (char *)(ptr
+ ciph
->len
);
300 if (dv
->sct
== DV_SCT_HEADER
&& dv
->dseq
== 0) {
302 system
= ciph
->fdf
.dv
.fs
;
303 fprintf(stderr
, "%s\n", system_name
[system
]);
308 (dv
->payload
[0] & DV_DSF_12
) == 0)
309 dv
->payload
[0] |= DV_DSF_12
;
310 nb
= nblocks
[system
];
311 fprintf(stderr
, "%d", k
%10);
313 if (m
> 0 && m
!= nb
) {
314 /* padding bad frame */
315 npad
= ((nb
- m
) % nb
);
318 fprintf(stderr
, "(%d blocks padded)",
321 memcpy(dest
, fPad
, npad
);
322 dest
= (char*)dest
+ npad
;
326 if (k
% frame_rate
[system
] == 0) {
328 fprintf(stderr
, "\n");
336 memcpy(dest
, dv
, DV_DSIZE
);
337 dest
= (char*)dest
+ DV_DSIZE
;
339 ptr
= (u_int32_t
*)dv
;
346 FireWireCard::MpegtsRead(void** buffer
)
348 struct fw_isochreq isoreq
;
349 struct fw_isobufreq bufreq
;
350 char ich
= TAG
|CHANNEL
;
354 bufreq
.rx
.nchunk
= MPEG_NCHUNK
;
355 bufreq
.rx
.npacket
= MPEG_NPACKET_R
;
356 bufreq
.rx
.psize
= MPEG_PSIZE
;
357 bufreq
.tx
.nchunk
= 0;
358 bufreq
.tx
.npacket
= 0;
360 if (ioctl(fDev
, FW_SSTBUF
, &bufreq
) < 0)
363 isoreq
.ch
= ich
& 0x3f;
364 isoreq
.tag
= (ich
>> 6) & 3;
366 if (ioctl(fDev
, FW_SRSTREAM
, &isoreq
) < 0)
369 len
= read(fDev
, fBuf
, MPEG_RBUFSIZE
);
371 if (errno
== EAGAIN
) {
372 fprintf(stderr
, "(EAGAIN) - push 'Play'?\n");
375 fprintf(stderr
, "read failed");
384 FireWireCard::MpegtsExtract(void* dest
, void** src
, ssize_t
* sizeUsed
)
389 struct mpeg_pldt
* pld
;
390 int pkt_size
, startwr
;
392 ptr
= (uint32_t *)(*src
);
395 pkt
= (struct fw_pkt
*) ptr
;
396 /* there is no CRC in the 1394 header */
397 ciph
= (struct ciphdr
*)(ptr
+ 1); /* skip iso header */
398 if (ciph
->fmt
!= CIP_FMT_MPEG
) {
399 fprintf(stderr
, "unknown format 0x%x", ciph
->fmt
);
403 fprintf(stderr
, "unsupported MPEG TS stream, fn=%d (only"
404 "fn=3 is supported)", ciph
->fn
);
407 ptr
= (uint32_t*) (ciph
+ 1); /* skip cip header */
409 if (pkt
->mode
.stream
.len
<= sizeof(struct ciphdr
)) {
411 /* tlen needs to be decremented before end of the loop */
415 /* This is a condition that needs to be satisfied to start
417 if (ciph
->dbc
% (1<<ciph
->fn
) == 0)
419 /* Read out all the MPEG TS data blocks from current packet */
420 for (pld
= (struct mpeg_pldt
*)ptr
;
421 (intptr_t)pld
< (intptr_t)((char*)ptr
+
422 pkt
->mode
.stream
.len
- sizeof(struct ciphdr
));
425 memcpy(dest
, pld
->payload
, sizeof(pld
->payload
));
426 dest
= (char*)dest
+ sizeof(pld
->payload
);
431 /* CRCs are removed from both header and trailer
432 so that only 4 bytes of 1394 header remains */
433 pkt_size
= pkt
->mode
.stream
.len
+ 4;
434 ptr
= (uint32_t*)((intptr_t)pkt
+ pkt_size
);