1 /* 2 * FireWire DV media addon for Haiku 3 * 4 * Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn) 5 * Distributed under the terms of the MIT License. 6 * 7 */ 8 /* 9 * Copyright (C) 2003 10 * Hidetoshi Shimokawa. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 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: 22 * 23 * This product includes software developed by Hidetoshi Shimokawa. 24 * 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. 28 * 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 39 * SUCH DAMAGE. 40 */ 41 42 #include "FireWireCard.h" 43 44 #include <stdlib.h> 45 #include <stdio.h> 46 #include <string.h> 47 #include <fcntl.h> 48 #include <unistd.h> 49 #include <sys/ioctl.h> 50 #include <OS.h> 51 #include <stdint.h> 52 #include <errno.h> 53 54 #include "glue.h" 55 56 #define TAG (1<<6) 57 #define CHANNEL 63 58 59 /* for DV format */ 60 #define FIX_FRAME 1 61 62 struct frac { 63 int n,d; 64 }; 65 66 struct frac frame_cycle[2] = { 67 {8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */ 68 {320, 1}, /* PAL 8000 cycle / 25 Hz */ 69 }; 70 int npackets[] = { 71 250 /* NTSC */, 72 300 /* PAL */ 73 }; 74 struct frac pad_rate[2] = { 75 {203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */ 76 {1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */ 77 }; 78 char *system_name[] = {"NTSC", "PAL"}; 79 int frame_rate[] = {30, 25}; 80 81 #define DV_PSIZE 512 82 #define DV_DSIZE 480 83 #define DV_NCHUNK 64 84 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 92 93 /* for MPEGTS format */ 94 typedef uint8_t mpeg_ts_pld[188]; 95 96 struct mpeg_pldt { 97 #if BYTE_ORDER == BIG_ENDIAN 98 uint32_t :7, 99 c_count:13, 100 c_offset:12; 101 #else /* BYTE_ORDER != BIG_ENDIAN */ 102 uint32_t c_offset:12, 103 c_count:13, 104 :7; 105 #endif /* BYTE_ORDER == BIG_ENDIAN */ 106 mpeg_ts_pld payload; 107 }; 108 109 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) 114 115 116 FireWireCard::FireWireCard(const char* path) 117 : fInitStatus(B_OK), 118 fDev(-1), 119 fBuf(NULL), 120 fPad(NULL) 121 { 122 printf("FireWireCard opening %s\n", path); 123 124 fDev = open(path, O_RDWR); 125 if (fDev < 0) { 126 printf("FireWireCard opening %s failed\n", path); 127 fInitStatus = B_ERROR; 128 return; 129 } 130 } 131 132 133 FireWireCard::~FireWireCard() 134 { 135 if (fDev > 0) 136 close(fDev); 137 } 138 139 140 status_t 141 FireWireCard::InitCheck() 142 { 143 return fInitStatus; 144 } 145 146 147 ssize_t 148 FireWireCard::Read(void** data) 149 { 150 if (fFormat == FMT_MPEGTS) 151 return MpegtsRead(data); 152 else 153 return DvRead(data); 154 } 155 156 157 status_t 158 FireWireCard::Extract(void* dest, void** src, ssize_t* sizeUsed) 159 { 160 if (fFormat == FMT_MPEGTS) 161 return MpegtsExtract(dest, src, sizeUsed); 162 else 163 return DvExtract(dest, src, sizeUsed); 164 } 165 166 167 void 168 FireWireCard::GetBufInfo(size_t* rbufsize, int* rcount) 169 { 170 *rbufsize = fRbufSize; 171 *rcount = fRcount; 172 } 173 174 175 status_t 176 FireWireCard::DetectRecvFn() 177 { 178 char* buf; 179 char ich = TAG | CHANNEL; 180 struct fw_isochreq isoreq; 181 struct fw_isobufreq bufreq; 182 int len; 183 u_int32_t* ptr; 184 struct ciphdr* ciph; 185 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; 191 bufreq.tx.psize = 0; 192 193 if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0) 194 return errno; 195 196 isoreq.ch = ich & 0x3f; 197 isoreq.tag = (ich >> 6) & 3; 198 199 if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0) 200 return errno; 201 202 buf = (char*)malloc(1024*16); 203 len = read(fDev, buf, 1024*16); 204 if (len < 0) 205 return errno; 206 ptr = (u_int32_t*) buf; 207 ciph = (struct ciphdr*)(ptr + 1); 208 209 switch(ciph->fmt) { 210 case CIP_FMT_DVCR: 211 fprintf(stderr, "Detected DV format on input.\n"); 212 fFormat = FMT_DV; 213 fBuf = malloc(DV_RBUFSIZE); 214 fRbufSize = DV_PSIZE; 215 fRcount = DV_NPACKET_R; 216 fPad = malloc(DV_DSIZE*DV_MAXBLOCKS); 217 memset(fPad, 0xff, DV_DSIZE*DV_MAXBLOCKS); 218 break; 219 case CIP_FMT_MPEG: 220 fprintf(stderr, "Detected MPEG TS format on input.\n"); 221 fFormat = FMT_MPEGTS; 222 fBuf = malloc(MPEG_RBUFSIZE); 223 fRbufSize = MPEG_PSIZE; 224 fRcount = MPEG_NPACKET_R; 225 break; 226 default: 227 fprintf(stderr, "Unsupported format for receiving: fmt=0x%x", ciph->fmt); 228 } 229 free(buf); 230 return B_OK; 231 } 232 233 234 ssize_t 235 FireWireCard::DvRead(void** buffer) 236 { 237 struct fw_isochreq isoreq; 238 struct fw_isobufreq bufreq; 239 ssize_t len; 240 char ich = TAG|CHANNEL; 241 242 bufreq.rx.nchunk = DV_NCHUNK; 243 bufreq.rx.npacket = DV_NPACKET_R; 244 bufreq.rx.psize = DV_PSIZE; 245 bufreq.tx.nchunk = 0; 246 bufreq.tx.npacket = 0; 247 bufreq.tx.psize = 0; 248 if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0) 249 return errno; 250 251 isoreq.ch = ich & 0x3f; 252 isoreq.tag = (ich >> 6) & 3; 253 254 if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0) 255 return errno; 256 257 len = read(fDev, fBuf, DV_RBUFSIZE); 258 if (len < 0) { 259 if (errno == EAGAIN) { 260 fprintf(stderr, "(EAGAIN) - push 'Play'?\n"); 261 fflush(stderr); 262 } else 263 fprintf(stderr, "read failed"); 264 return errno; 265 } 266 *buffer = fBuf; 267 return len; 268 } 269 270 271 status_t 272 FireWireCard::DvExtract(void* dest, void** src, ssize_t* sizeUsed) 273 { 274 struct dvdbc* dv; 275 struct ciphdr* ciph; 276 struct fw_pkt* pkt; 277 u_int32_t* ptr; 278 int nblocks[] = {250 /* NTSC */, 300 /* PAL */}; 279 int npad, k, m, system = -1, nb; 280 281 k = m = 0; 282 ptr = (u_int32_t*) (*src); 283 284 pkt = (struct fw_pkt*) ptr; 285 ciph = (struct ciphdr*)(ptr + 1); /* skip iso header */ 286 if (ciph->fmt != CIP_FMT_DVCR) { 287 fprintf(stderr, "unknown format 0x%x", ciph->fmt); 288 return B_ERROR; 289 } 290 ptr = (u_int32_t*) (ciph + 1); /* skip cip header */ 291 if (pkt->mode.stream.len <= sizeof(struct ciphdr)) 292 /* no payload */ 293 return B_ERROR; 294 for (dv = (struct dvdbc*)ptr; 295 (char*)dv < (char *)(ptr + ciph->len); 296 dv+=6) { 297 298 if (dv->sct == DV_SCT_HEADER && dv->dseq == 0) { 299 if (system < 0) { 300 system = ciph->fdf.dv.fs; 301 fprintf(stderr, "%s\n", system_name[system]); 302 } 303 304 /* Fix DSF bit */ 305 if (system == 1 && 306 (dv->payload[0] & DV_DSF_12) == 0) 307 dv->payload[0] |= DV_DSF_12; 308 nb = nblocks[system]; 309 fprintf(stderr, "%d", k%10); 310 #if FIX_FRAME 311 if (m > 0 && m != nb) { 312 /* padding bad frame */ 313 npad = ((nb - m) % nb); 314 if (npad < 0) 315 npad += nb; 316 fprintf(stderr, "(%d blocks padded)", 317 npad); 318 npad *= DV_DSIZE; 319 memcpy(dest, fPad, npad); 320 dest = (char*)dest + npad; 321 } 322 #endif 323 k++; 324 if (k % frame_rate[system] == 0) { 325 /* every second */ 326 fprintf(stderr, "\n"); 327 } 328 fflush(stderr); 329 m = 0; 330 } 331 if (k == 0) 332 continue; 333 m++; 334 memcpy(dest, dv, DV_DSIZE); 335 dest = (char*)dest + DV_DSIZE; 336 } 337 ptr = (u_int32_t*)dv; 338 *src = ptr; 339 return B_OK; 340 } 341 342 343 ssize_t 344 FireWireCard::MpegtsRead(void** buffer) 345 { 346 struct fw_isochreq isoreq; 347 struct fw_isobufreq bufreq; 348 char ich = TAG|CHANNEL; 349 ssize_t len; 350 351 352 bufreq.rx.nchunk = MPEG_NCHUNK; 353 bufreq.rx.npacket = MPEG_NPACKET_R; 354 bufreq.rx.psize = MPEG_PSIZE; 355 bufreq.tx.nchunk = 0; 356 bufreq.tx.npacket = 0; 357 bufreq.tx.psize = 0; 358 if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0) 359 return errno; 360 361 isoreq.ch = ich & 0x3f; 362 isoreq.tag = (ich >> 6) & 3; 363 364 if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0) 365 return errno; 366 367 len = read(fDev, fBuf, MPEG_RBUFSIZE); 368 if (len < 0) { 369 if (errno == EAGAIN) { 370 fprintf(stderr, "(EAGAIN) - push 'Play'?\n"); 371 fflush(stderr); 372 } else 373 fprintf(stderr, "read failed"); 374 return errno; 375 } 376 *buffer = fBuf; 377 return len; 378 } 379 380 381 status_t 382 FireWireCard::MpegtsExtract(void* dest, void** src, ssize_t* sizeUsed) 383 { 384 uint32_t* ptr; 385 struct fw_pkt* pkt; 386 struct ciphdr* ciph; 387 struct mpeg_pldt* pld; 388 int pkt_size, startwr; 389 390 ptr = (uint32_t *)(*src); 391 startwr = 0; 392 393 pkt = (struct fw_pkt*) ptr; 394 /* there is no CRC in the 1394 header */ 395 ciph = (struct ciphdr*)(ptr + 1); /* skip iso header */ 396 if (ciph->fmt != CIP_FMT_MPEG) { 397 fprintf(stderr, "unknown format 0x%x", ciph->fmt); 398 return B_ERROR; 399 } 400 if (ciph->fn != 3) { 401 fprintf(stderr, "unsupported MPEG TS stream, fn=%d (only" 402 "fn=3 is supported)", ciph->fn); 403 return B_ERROR; 404 } 405 ptr = (uint32_t*) (ciph + 1); /* skip cip header */ 406 407 if (pkt->mode.stream.len <= sizeof(struct ciphdr)) { 408 /* no payload */ 409 /* tlen needs to be decremented before end of the loop */ 410 goto next; 411 } 412 413 /* This is a condition that needs to be satisfied to start 414 writing the data */ 415 if (ciph->dbc % (1<<ciph->fn) == 0) 416 startwr = 1; 417 /* Read out all the MPEG TS data blocks from current packet */ 418 for (pld = (struct mpeg_pldt *)ptr; 419 (intptr_t)pld < (intptr_t)((char*)ptr + 420 pkt->mode.stream.len - sizeof(struct ciphdr)); 421 pld++) { 422 if (startwr == 1) { 423 memcpy(dest, pld->payload, sizeof(pld->payload)); 424 dest = (char*)dest + sizeof(pld->payload); 425 } 426 } 427 428 next: 429 /* CRCs are removed from both header and trailer 430 so that only 4 bytes of 1394 header remains */ 431 pkt_size = pkt->mode.stream.len + 4; 432 ptr = (uint32_t*)((intptr_t)pkt + pkt_size); 433 *src = ptr; 434 return B_OK; 435 } 436 437