2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #ifndef MPLAYER_VCD_READ_FBSD_H
20 #define MPLAYER_VCD_READ_FBSD_H
22 #define _XOPEN_SOURCE 500
24 #include <sys/types.h>
28 #include <sys/ioctl.h>
30 #include <libavutil/intreadwrite.h>
32 #if defined(__NetBSD__) || defined(__OpenBSD__)
36 #include <sys/scsiio.h>
37 #define TOCADDR(te) ((te).data->addr)
38 #define READ_TOC CDIOREADTOCENTRYS
40 #include <sys/cdrio.h>
41 #define TOCADDR(te) ((te).entry.addr)
42 #define READ_TOC CDIOREADTOCENTRY
46 //=================== VideoCD ==========================
47 #define CDROM_LEADOUT 0xAA
52 uint8_t subheader
[8];
58 typedef struct ioc_read_toc_entry vcd_tocentry
;
60 typedef struct ioc_read_toc_single_entry vcd_tocentry
;
63 typedef struct mp_vcd_priv_st
{
67 struct cd_toc_entry entry_data
;
71 struct ioc_toc_header tochdr
;
75 vcd_set_msf(mp_vcd_priv_t
* vcd
, unsigned int sect
)
78 vcd
->entry
.data
= &vcd
->entry_data
;
81 TOCADDR(vcd
->entry
).msf
.frame
= sect
% 75;
83 TOCADDR(vcd
->entry
).msf
.second
= sect
% 60;
85 TOCADDR(vcd
->entry
).msf
.minute
= sect
;
89 vcd_inc_msf(mp_vcd_priv_t
* vcd
)
92 vcd
->entry
.data
= &vcd
->entry_data
;
94 TOCADDR(vcd
->entry
).msf
.frame
++;
95 if (TOCADDR(vcd
->entry
).msf
.frame
==75){
96 TOCADDR(vcd
->entry
).msf
.frame
=0;
97 TOCADDR(vcd
->entry
).msf
.second
++;
98 if (TOCADDR(vcd
->entry
).msf
.second
==60){
99 TOCADDR(vcd
->entry
).msf
.second
=0;
100 TOCADDR(vcd
->entry
).msf
.minute
++;
105 static inline unsigned int
106 vcd_get_msf(mp_vcd_priv_t
* vcd
)
109 vcd
->entry
.data
= &vcd
->entry_data
;
111 return TOCADDR(vcd
->entry
).msf
.frame
+
112 (TOCADDR(vcd
->entry
).msf
.second
+
113 TOCADDR(vcd
->entry
).msf
.minute
* 60) * 75 - 150;
117 * \brief read a TOC entry
118 * \param fd device to read from
119 * \param dst buffer to read data into
120 * \param nr track number to read info for
121 * \return 1 on success, 0 on failure
124 read_toc_entry(mp_vcd_priv_t
*vcd
, int nr
)
126 vcd
->entry
.address_format
= CD_MSF_FORMAT
;
128 vcd
->entry
.data_len
= sizeof(struct cd_toc_entry
);
129 vcd
->entry
.data
= &vcd
->entry_data
;
130 vcd
->entry
.starting_track
= nr
;
132 vcd
->entry
.track
= nr
;
134 if (ioctl(vcd
->fd
, READ_TOC
, &vcd
->entry
) == -1) {
135 mp_msg(MSGT_OPEN
,MSGL_ERR
,"read CDROM toc entry: %s\n",strerror(errno
));
142 vcd_seek_to_track(mp_vcd_priv_t
* vcd
, int track
)
144 if (!read_toc_entry(vcd
, track
))
146 return VCD_SECTOR_DATA
* vcd_get_msf(vcd
);
150 vcd_get_track_end(mp_vcd_priv_t
* vcd
, int track
)
152 if (!read_toc_entry(vcd
,
153 track
< vcd
->tochdr
.ending_track
? track
+ 1 : CDROM_LEADOUT
))
155 return VCD_SECTOR_DATA
* vcd_get_msf(vcd
);
158 static mp_vcd_priv_t
*
161 struct ioc_toc_header tochdr
;
163 int i
, last_startsect
;
164 if (ioctl(fd
, CDIOREADTOCHEADER
, &tochdr
) == -1) {
165 mp_msg(MSGT_OPEN
,MSGL_ERR
,"read CDROM toc header: %s\n",strerror(errno
));
168 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VCD_START_TRACK=%d\n", tochdr
.starting_track
);
169 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VCD_END_TRACK=%d\n", tochdr
.ending_track
);
170 vcd
= malloc(sizeof(mp_vcd_priv_t
));
172 vcd
->tochdr
= tochdr
;
173 for (i
= tochdr
.starting_track
; i
<= tochdr
.ending_track
+ 1; i
++) {
174 if (!read_toc_entry(vcd
,
175 i
<= tochdr
.ending_track
? i
: CDROM_LEADOUT
)) {
180 if (i
<= tochdr
.ending_track
)
181 mp_msg(MSGT_OPEN
,MSGL_INFO
,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n",
183 (int)vcd
->entry
.starting_track
,
184 (int)vcd
->entry
.data
->addr_type
,
185 (int)vcd
->entry
.data
->control
,
187 (int)vcd
->entry
.track
,
188 (int)vcd
->entry
.entry
.addr_type
,
189 (int)vcd
->entry
.entry
.control
,
191 (int)vcd
->entry
.address_format
,
192 (int)TOCADDR(vcd
->entry
).msf
.minute
,
193 (int)TOCADDR(vcd
->entry
).msf
.second
,
194 (int)TOCADDR(vcd
->entry
).msf
.frame
197 if (mp_msg_test(MSGT_IDENTIFY
, MSGL_INFO
))
199 int startsect
= vcd_get_msf(vcd
);
200 if (i
> tochdr
.starting_track
)
202 // convert duraion to MSF
203 vcd_set_msf(vcd
, startsect
- last_startsect
);
204 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
205 "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n",
207 TOCADDR(vcd
->entry
).msf
.minute
,
208 TOCADDR(vcd
->entry
).msf
.second
,
209 TOCADDR(vcd
->entry
).msf
.frame
);
211 last_startsect
= startsect
;
217 static int vcd_end_track(mp_vcd_priv_t
* vcd
)
219 return vcd
->tochdr
.ending_track
;
223 vcd_read(mp_vcd_priv_t
* vcd
, char *mem
)
227 int lba
= vcd_get_msf(vcd
);
233 memset(&sc
, 0, sizeof(sc
));
235 sc
.cmd
[1] = 5 << 2; // mode2/form2
236 AV_WB32(&sc
.cmd
[2], lba
);
237 AV_WB24(&sc
.cmd
[6], blocks
);
238 sc
.cmd
[9] = 1 << 4; // user data only
239 sc
.cmd
[10] = 0; // no subchannel
241 sc
.databuf
= (caddr_t
) mem
;
242 sc
.datalen
= VCD_SECTOR_DATA
;
243 sc
.senselen
= sizeof(sc
.sense
);
244 sc
.flags
= SCCMD_READ
;
246 rc
= ioctl(vcd
->fd
, SCIOCCOMMAND
, &sc
);
248 mp_msg(MSGT_STREAM
,MSGL_ERR
,"SCIOCCOMMAND: %s\n",strerror(errno
));
251 if (sc
.retsts
|| sc
.error
) {
252 mp_msg(MSGT_STREAM
,MSGL_ERR
,"scsi command failed: status %d error %d\n",
257 if (pread(vcd
->fd
,&vcd
->buf
,VCD_SECTOR_SIZE
,vcd_get_msf(vcd
)*VCD_SECTOR_SIZE
)
258 != VCD_SECTOR_SIZE
) return 0; // EOF?
260 memcpy(mem
,vcd
->buf
.data
,VCD_SECTOR_DATA
);
263 return VCD_SECTOR_DATA
;
266 #endif /* MPLAYER_VCD_READ_FBSD_H */