1145519Sdarrenr/*
2145510Sdarrenr * FireWire DV media addon for Haiku
3145510Sdarrenr *
4255332Scy * Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
5145510Sdarrenr * Distributed under the terms of the MIT License.
6145510Sdarrenr *
7145510Sdarrenr */
8145510Sdarrenr/*
9145510Sdarrenr * Copyright (C) 2003
10255332Scy * 	Hidetoshi Shimokawa. All rights reserved.
11145510Sdarrenr *
12145510Sdarrenr * Redistribution and use in source and binary forms, with or without
13145510Sdarrenr * modification, are permitted provided that the following conditions
14145510Sdarrenr * are met:
15145510Sdarrenr * 1. Redistributions of source code must retain the above copyright
16255332Scy *    notice, this list of conditions and the following disclaimer.
17145510Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright
18145510Sdarrenr *    notice, this list of conditions and the following disclaimer in the
19145510Sdarrenr *    documentation and/or other materials provided with the distribution.
20369245Sgit2svn * 3. All advertising materials mentioning features or use of this software
21145510Sdarrenr *    must display the following acknowledgement:
22145510Sdarrenr *
23145510Sdarrenr *	This product includes software developed by Hidetoshi Shimokawa.
24145510Sdarrenr *
25145510Sdarrenr * 4. Neither the name of the author nor the names of its contributors
26145510Sdarrenr *    may be used to endorse or promote products derived from this software
27145510Sdarrenr *    without specific prior written permission.
28369245Sgit2svn *
29369245Sgit2svn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30369245Sgit2svn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31145510Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32145510Sdarrenr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33145510Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34145510Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35255332Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36145510Sdarrenr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37369245Sgit2svn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38369245Sgit2svn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39369245Sgit2svn * SUCH DAMAGE.
40369245Sgit2svn */
41369245Sgit2svn
42369245Sgit2svn#include "FireWireCard.h"
43369245Sgit2svn
44369245Sgit2svn#include <stdlib.h>
45145510Sdarrenr#include <stdio.h>
46369245Sgit2svn#include <string.h>
47369245Sgit2svn#include <fcntl.h>
48369245Sgit2svn#include <unistd.h>
49369245Sgit2svn#include <sys/ioctl.h>
50145510Sdarrenr#include <OS.h>
51145510Sdarrenr#include <stdint.h>
52145510Sdarrenr#include <errno.h>
53145510Sdarrenr
54145510Sdarrenr#include "glue.h"
55145510Sdarrenr
56255332Scy#define TAG	(1<<6)
57255332Scy#define CHANNEL	63
58255332Scy
59145510Sdarrenr/* for DV format */
60145510Sdarrenr#define FIX_FRAME	1
61145510Sdarrenr
62145510Sdarrenrstruct frac {
63145510Sdarrenr	int n,d;
64145510Sdarrenr};
65145510Sdarrenr
66145510Sdarrenrstruct frac frame_cycle[2]  = {
67145510Sdarrenr	{8000*100, 2997},	/* NTSC 8000 cycle / 29.97 Hz */
68145510Sdarrenr	{320, 1},		/* PAL  8000 cycle / 25 Hz */
69145510Sdarrenr};
70255332Scyint npackets[] = {
71255332Scy	250		/* NTSC */,
72145510Sdarrenr	300		/* PAL */
73255332Scy};
74145510Sdarrenrstruct frac pad_rate[2]  = {
75145510Sdarrenr	{203, 2997},	/* = (8000 - 29.97 * 250)/(29.97 * 250) */
76145510Sdarrenr	{1, 15},	/* = (8000 - 25 * 300)/(25 * 300) */
77145510Sdarrenr};
78255332Scyconst char *system_name[] = {"NTSC", "PAL"};
79255332Scyint frame_rate[] = {30, 25};
80255332Scy
81145510Sdarrenr#define DV_PSIZE 512
82145510Sdarrenr#define DV_DSIZE 480
83145510Sdarrenr#define DV_NCHUNK 64
84145510Sdarrenr
85145510Sdarrenr#define DV_NPACKET_R 256
86255332Scy#define DV_NPACKET_T 255
87255332Scy#define DV_TNBUF 100	/* XXX too large value causes block noise */
88255332Scy#define DV_NEMPTY 10	/* depends on DV_TNBUF */
89145510Sdarrenr#define DV_RBUFSIZE (DV_PSIZE * DV_NPACKET_R)
90145510Sdarrenr#define DV_MAXBLOCKS (300)
91145510Sdarrenr#define DV_CYCLE_FRAC 0xc00
92145510Sdarrenr
93145510Sdarrenr/* for MPEGTS format */
94145510Sdarrenrtypedef uint8_t mpeg_ts_pld[188];
95145510Sdarrenr
96145510Sdarrenrstruct mpeg_pldt {
97145510Sdarrenr#if BYTE_ORDER == BIG_ENDIAN
98145510Sdarrenr	uint32_t	:7,
99145510Sdarrenr				c_count:13,
100145510Sdarrenr				c_offset:12;
101145510Sdarrenr#else /* BYTE_ORDER != BIG_ENDIAN */
102145510Sdarrenr	uint32_t	c_offset:12,
103145510Sdarrenr				c_count:13,
104145510Sdarrenr				:7;
105145510Sdarrenr#endif /* BYTE_ORDER == BIG_ENDIAN */
106145510Sdarrenr	mpeg_ts_pld payload;
107145510Sdarrenr};
108145510Sdarrenr
109255332Scy
110145510Sdarrenr#define	MPEG_NCHUNK 8
111145510Sdarrenr#define	MPEG_PSIZE 596
112255332Scy#define	MPEG_NPACKET_R 4096
113145510Sdarrenr#define	MPEG_RBUFSIZE (MPEG_PSIZE * MPEG_NPACKET_R)
114145510Sdarrenr
115145510Sdarrenr
116145510SdarrenrFireWireCard::FireWireCard(const char* path)
117145510Sdarrenr	: fInitStatus(B_OK),
118145510Sdarrenr	fDev(-1),
119145510Sdarrenr	fBuf(NULL),
120255332Scy	fPad(NULL)
121255332Scy{
122255332Scy	printf("FireWireCard opening %s\n", path);
123145510Sdarrenr
124255332Scy	fDev = open(path, O_RDWR);
125145510Sdarrenr	if (fDev < 0) {
126145510Sdarrenr		printf("FireWireCard opening %s failed\n", path);
127145510Sdarrenr		fInitStatus = B_ERROR;
128145510Sdarrenr		return;
129145510Sdarrenr	}
130145510Sdarrenr}
131145510Sdarrenr
132145510Sdarrenr
133145510SdarrenrFireWireCard::~FireWireCard()
134145510Sdarrenr{
135145510Sdarrenr	if (fDev > 0)
136145510Sdarrenr		close(fDev);
137145510Sdarrenr}
138145510Sdarrenr
139145510Sdarrenr
140145510Sdarrenrstatus_t
141145510SdarrenrFireWireCard::InitCheck()
142145510Sdarrenr{
143145510Sdarrenr	return fInitStatus;
144145510Sdarrenr}
145145510Sdarrenr
146145510Sdarrenr
147145510Sdarrenrssize_t
148145510SdarrenrFireWireCard::Read(void** data)
149145510Sdarrenr{
150145510Sdarrenr	if (fFormat == FMT_MPEGTS)
151145510Sdarrenr		return MpegtsRead(data);
152145510Sdarrenr	else
153145510Sdarrenr		return DvRead(data);
154145510Sdarrenr}
155145510Sdarrenr
156145510Sdarrenr
157145510Sdarrenrstatus_t
158145510SdarrenrFireWireCard::Extract(void* dest, void** src, ssize_t* sizeUsed)
159145510Sdarrenr{
160145510Sdarrenr	if (fFormat == FMT_MPEGTS)
161145510Sdarrenr		return MpegtsExtract(dest, src, sizeUsed);
162145510Sdarrenr	else
163145510Sdarrenr		return DvExtract(dest, src, sizeUsed);
164145510Sdarrenr}
165145510Sdarrenr
166145510Sdarrenr
167145510Sdarrenrvoid
168145510SdarrenrFireWireCard::GetBufInfo(size_t* rbufsize, int* rcount)
169255332Scy{
170145510Sdarrenr	*rbufsize = fRbufSize;
171145510Sdarrenr	*rcount = fRcount;
172145510Sdarrenr}
173145510Sdarrenr
174145510Sdarrenr
175255332Scystatus_t
176255332ScyFireWireCard::DetectRecvFn()
177145510Sdarrenr{
178145510Sdarrenr	char* buf;
179145510Sdarrenr	char ich = TAG | CHANNEL;
180145510Sdarrenr	struct fw_isochreq isoreq;
181145510Sdarrenr	struct fw_isobufreq bufreq;
182145510Sdarrenr	int len;
183145510Sdarrenr	u_int32_t* ptr;
184145510Sdarrenr	struct ciphdr* ciph;
185145510Sdarrenr
186145510Sdarrenr	bufreq.rx.nchunk = 8;
187145510Sdarrenr	bufreq.rx.npacket = 16;
188145510Sdarrenr	bufreq.rx.psize = 1024;
189145510Sdarrenr	bufreq.tx.nchunk = 0;
190145510Sdarrenr	bufreq.tx.npacket = 0;
191145510Sdarrenr	bufreq.tx.psize = 0;
192255332Scy
193145510Sdarrenr	if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0)
194145510Sdarrenr		return errno;
195145510Sdarrenr
196145510Sdarrenr	isoreq.ch = ich & 0x3f;
197145510Sdarrenr	isoreq.tag = (ich >> 6) & 3;
198145510Sdarrenr
199145510Sdarrenr	if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0)
200145510Sdarrenr		return errno;
201145510Sdarrenr
202145510Sdarrenr	buf = (char*)malloc(1024*16);
203145510Sdarrenr	len = read(fDev, buf, 1024*16);
204145510Sdarrenr	if (len < 0) {
205145510Sdarrenr		free(buf);
206161357Sguido		return errno;
207145510Sdarrenr	}
208145510Sdarrenr	ptr = (u_int32_t*) buf;
209145510Sdarrenr	ciph = (struct ciphdr*)(ptr + 1);
210255332Scy
211145510Sdarrenr	switch(ciph->fmt) {
212145510Sdarrenr		case CIP_FMT_DVCR:
213145510Sdarrenr			fprintf(stderr, "Detected DV format on input.\n");
214145510Sdarrenr			fFormat = FMT_DV;
215145510Sdarrenr			fBuf = malloc(DV_RBUFSIZE);
216145510Sdarrenr			fRbufSize = DV_PSIZE;
217145510Sdarrenr			fRcount = DV_NPACKET_R;
218255332Scy			fPad = malloc(DV_DSIZE*DV_MAXBLOCKS);
219145510Sdarrenr			memset(fPad, 0xff, DV_DSIZE*DV_MAXBLOCKS);
220255332Scy			break;
221145510Sdarrenr		case CIP_FMT_MPEG:
222255332Scy			fprintf(stderr, "Detected MPEG TS format on input.\n");
223145510Sdarrenr			fFormat = FMT_MPEGTS;
224145510Sdarrenr			fBuf = malloc(MPEG_RBUFSIZE);
225255332Scy			fRbufSize = MPEG_PSIZE;
226255332Scy			fRcount = MPEG_NPACKET_R;
227255332Scy			break;
228145510Sdarrenr		default:
229255332Scy			fprintf(stderr, "Unsupported format for receiving: fmt=0x%x", ciph->fmt);
230145510Sdarrenr	}
231145510Sdarrenr	free(buf);
232145510Sdarrenr	return B_OK;
233145510Sdarrenr}
234255332Scy
235255332Scy
236145510Sdarrenrssize_t
237145510SdarrenrFireWireCard::DvRead(void** buffer)
238145510Sdarrenr{
239145510Sdarrenr	struct fw_isochreq isoreq;
240145510Sdarrenr	struct fw_isobufreq bufreq;
241145510Sdarrenr	ssize_t len;
242145510Sdarrenr	char ich = TAG|CHANNEL;
243145510Sdarrenr
244145510Sdarrenr	bufreq.rx.nchunk = DV_NCHUNK;
245145510Sdarrenr	bufreq.rx.npacket = DV_NPACKET_R;
246145510Sdarrenr	bufreq.rx.psize = DV_PSIZE;
247145510Sdarrenr	bufreq.tx.nchunk = 0;
248145510Sdarrenr	bufreq.tx.npacket = 0;
249145510Sdarrenr	bufreq.tx.psize = 0;
250145510Sdarrenr	if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0)
251255332Scy		return errno;
252255332Scy
253255332Scy	isoreq.ch = ich & 0x3f;
254255332Scy	isoreq.tag = (ich >> 6) & 3;
255145510Sdarrenr
256145510Sdarrenr	if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0)
257145510Sdarrenr		return errno;
258145510Sdarrenr
259255332Scy	len = read(fDev, fBuf, DV_RBUFSIZE);
260255332Scy	if (len < 0) {
261255332Scy		if (errno == EAGAIN) {
262145510Sdarrenr			fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
263145510Sdarrenr			fflush(stderr);
264145510Sdarrenr		} else
265145510Sdarrenr			fprintf(stderr, "read failed");
266255332Scy		return errno;
267145510Sdarrenr	}
268145510Sdarrenr	*buffer = fBuf;
269145510Sdarrenr	return len;
270145510Sdarrenr}
271145510Sdarrenr
272145510Sdarrenr
273145510Sdarrenrstatus_t
274145510SdarrenrFireWireCard::DvExtract(void* dest, void** src, ssize_t* sizeUsed)
275145510Sdarrenr{
276145510Sdarrenr	struct dvdbc* dv;
277145510Sdarrenr	struct ciphdr* ciph;
278145510Sdarrenr	struct fw_pkt* pkt;
279145510Sdarrenr	u_int32_t* ptr;
280145510Sdarrenr	int nblocks[] = {250 /* NTSC */, 300 /* PAL */};
281145510Sdarrenr	int npad, k, m, system = -1, nb;
282145510Sdarrenr
283145510Sdarrenr	k = m = 0;
284145510Sdarrenr	ptr = (u_int32_t*) (*src);
285145510Sdarrenr
286145510Sdarrenr	pkt = (struct fw_pkt*) ptr;
287145510Sdarrenr	ciph = (struct ciphdr*)(ptr + 1);	/* skip iso header */
288145510Sdarrenr	if (ciph->fmt != CIP_FMT_DVCR) {
289145510Sdarrenr		fprintf(stderr, "unknown format 0x%x", ciph->fmt);
290283295Semaste		return B_ERROR;
291145510Sdarrenr	}
292145510Sdarrenr	ptr = (u_int32_t*) (ciph + 1);		/* skip cip header */
293145510Sdarrenr	if (pkt->mode.stream.len <= sizeof(struct ciphdr))
294145510Sdarrenr		/* no payload */
295145510Sdarrenr		return B_ERROR;
296145510Sdarrenr	for (dv = (struct dvdbc*)ptr;
297145510Sdarrenr			(char*)dv < (char *)(ptr + ciph->len);
298145510Sdarrenr			dv+=6) {
299145510Sdarrenr
300145510Sdarrenr		if  (dv->sct == DV_SCT_HEADER && dv->dseq == 0) {
301145510Sdarrenr			if (system < 0) {
302145510Sdarrenr				system = ciph->fdf.dv.fs;
303145510Sdarrenr				fprintf(stderr, "%s\n", system_name[system]);
304145510Sdarrenr			}
305255332Scy
306145510Sdarrenr			/* Fix DSF bit */
307145510Sdarrenr			if (system == 1 &&
308145510Sdarrenr				(dv->payload[0] & DV_DSF_12) == 0)
309145510Sdarrenr				dv->payload[0] |= DV_DSF_12;
310145510Sdarrenr			nb = nblocks[system];
311145510Sdarrenr			fprintf(stderr, "%d", k%10);
312145510Sdarrenr#if FIX_FRAME
313145510Sdarrenr			if (m > 0 && m != nb) {
314145510Sdarrenr				/* padding bad frame */
315145510Sdarrenr				npad = ((nb - m) % nb);
316145510Sdarrenr				if (npad < 0)
317145510Sdarrenr					npad += nb;
318145510Sdarrenr				fprintf(stderr, "(%d blocks padded)",
319145510Sdarrenr							npad);
320255332Scy				npad *= DV_DSIZE;
321145510Sdarrenr				memcpy(dest, fPad, npad);
322145510Sdarrenr				dest = (char*)dest + npad;
323145510Sdarrenr			}
324255332Scy#endif
325145510Sdarrenr			k++;
326145510Sdarrenr			if (k % frame_rate[system] == 0) {
327145510Sdarrenr				/* every second */
328145510Sdarrenr				fprintf(stderr, "\n");
329145510Sdarrenr			}
330145510Sdarrenr			fflush(stderr);
331145510Sdarrenr			m = 0;
332145510Sdarrenr		}
333145510Sdarrenr		if (k == 0)
334145510Sdarrenr			continue;
335145510Sdarrenr		m++;
336145510Sdarrenr		memcpy(dest, dv, DV_DSIZE);
337255332Scy		dest = (char*)dest + DV_DSIZE;
338145510Sdarrenr	}
339145510Sdarrenr	ptr = (u_int32_t*)dv;
340145510Sdarrenr	*src = ptr;
341255332Scy	return B_OK;
342145510Sdarrenr}
343145510Sdarrenr
344145510Sdarrenr
345145510Sdarrenrssize_t
346145510SdarrenrFireWireCard::MpegtsRead(void** buffer)
347145510Sdarrenr{
348145510Sdarrenr	struct fw_isochreq isoreq;
349255332Scy	struct fw_isobufreq bufreq;
350255332Scy	char ich = TAG|CHANNEL;
351255332Scy	ssize_t len;
352145510Sdarrenr
353145510Sdarrenr
354145510Sdarrenr	bufreq.rx.nchunk = MPEG_NCHUNK;
355145510Sdarrenr	bufreq.rx.npacket = MPEG_NPACKET_R;
356145510Sdarrenr	bufreq.rx.psize = MPEG_PSIZE;
357170268Sdarrenr	bufreq.tx.nchunk = 0;
358145510Sdarrenr	bufreq.tx.npacket = 0;
359145510Sdarrenr	bufreq.tx.psize = 0;
360170268Sdarrenr	if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0)
361170268Sdarrenr		return errno;
362145510Sdarrenr
363170268Sdarrenr	isoreq.ch = ich & 0x3f;
364145510Sdarrenr	isoreq.tag = (ich >> 6) & 3;
365145510Sdarrenr
366145510Sdarrenr	if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0)
367145510Sdarrenr		return errno;
368145510Sdarrenr
369145510Sdarrenr	len = read(fDev, fBuf, MPEG_RBUFSIZE);
370145510Sdarrenr	if (len < 0) {
371145510Sdarrenr		if (errno == EAGAIN) {
372255332Scy			fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
373255332Scy			fflush(stderr);
374255332Scy		} else
375255332Scy			fprintf(stderr, "read failed");
376255332Scy		return errno;
377255332Scy	}
378255332Scy	*buffer = fBuf;
379255332Scy	return len;
380255332Scy}
381255332Scy
382255332Scy
383255332Scystatus_t
384255332ScyFireWireCard::MpegtsExtract(void* dest, void** src, ssize_t* sizeUsed)
385255332Scy{
386145510Sdarrenr	uint32_t* ptr;
387145510Sdarrenr	struct fw_pkt* pkt;
388145510Sdarrenr	struct ciphdr* ciph;
389255332Scy	struct mpeg_pldt* pld;
390145510Sdarrenr	int pkt_size, startwr;
391145510Sdarrenr
392145510Sdarrenr	ptr = (uint32_t *)(*src);
393145510Sdarrenr	startwr = 0;
394255332Scy
395145510Sdarrenr	pkt = (struct fw_pkt*) ptr;
396145510Sdarrenr	/* there is no CRC in the 1394 header */
397255332Scy	ciph = (struct ciphdr*)(ptr + 1);	/* skip iso header */
398255332Scy	if (ciph->fmt != CIP_FMT_MPEG) {
399255332Scy		fprintf(stderr, "unknown format 0x%x", ciph->fmt);
400145510Sdarrenr		return B_ERROR;
401145510Sdarrenr	}
402313461Scy	if (ciph->fn != 3) {
403145510Sdarrenr		fprintf(stderr,	"unsupported MPEG TS stream, fn=%d (only"
404313441Scy			"fn=3 is supported)", ciph->fn);
405145510Sdarrenr		return B_ERROR;
406313441Scy	}
407145510Sdarrenr	ptr = (uint32_t*) (ciph + 1);		/* skip cip header */
408313441Scy
409313441Scy	if (pkt->mode.stream.len <= sizeof(struct ciphdr)) {
410313441Scy		/* no payload */
411313441Scy		/* tlen needs to be decremented before end of the loop */
412145510Sdarrenr		goto next;
413145510Sdarrenr	}
414145510Sdarrenr
415145510Sdarrenr	/* This is a condition that needs to be satisfied to start
416145510Sdarrenr	   writing the data */
417145510Sdarrenr	if (ciph->dbc % (1<<ciph->fn) == 0)
418145510Sdarrenr		startwr = 1;
419145510Sdarrenr	/* Read out all the MPEG TS data blocks from current packet */
420145510Sdarrenr	for (pld = (struct mpeg_pldt *)ptr;
421145510Sdarrenr	    (intptr_t)pld < (intptr_t)((char*)ptr +
422255332Scy	    pkt->mode.stream.len - sizeof(struct ciphdr));
423145510Sdarrenr	    pld++) {
424145510Sdarrenr		if (startwr == 1) {
425145510Sdarrenr			memcpy(dest, pld->payload, sizeof(pld->payload));
426145510Sdarrenr			dest = (char*)dest + sizeof(pld->payload);
427255332Scy		}
428145510Sdarrenr	}
429145510Sdarrenr
430145510Sdarrenrnext:
431145510Sdarrenr	/* CRCs are removed from both header and trailer
432145510Sdarrenr	so that only 4 bytes of 1394 header remains */
433255332Scy	pkt_size = pkt->mode.stream.len + 4;
434145510Sdarrenr	ptr = (uint32_t*)((intptr_t)pkt + pkt_size);
435145510Sdarrenr	*src = ptr;
436145510Sdarrenr	return B_OK;
437255332Scy}
438255332Scy
439255332Scy