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>
27 #include "libavutil/intreadwrite.h"
29 #include <sys/ioctl.h>
30 #if defined(__NetBSD__) || defined(__OpenBSD__)
34 #include <sys/scsiio.h>
35 #define TOCADDR(te) ((te).data->addr)
36 #define READ_TOC CDIOREADTOCENTRYS
38 #include <sys/cdrio.h>
39 #define TOCADDR(te) ((te).entry.addr)
40 #define READ_TOC CDIOREADTOCENTRY
44 //=================== VideoCD ==========================
45 #define CDROM_LEADOUT 0xAA
50 uint8_t subheader
[8];
56 typedef struct ioc_read_toc_entry vcd_tocentry
;
58 typedef struct ioc_read_toc_single_entry vcd_tocentry
;
61 typedef struct mp_vcd_priv_st
{
65 struct cd_toc_entry entry_data
;
69 struct ioc_toc_header tochdr
;
73 vcd_set_msf(mp_vcd_priv_t
* vcd
, unsigned int sect
)
76 vcd
->entry
.data
= &vcd
->entry_data
;
79 TOCADDR(vcd
->entry
).msf
.frame
= sect
% 75;
81 TOCADDR(vcd
->entry
).msf
.second
= sect
% 60;
83 TOCADDR(vcd
->entry
).msf
.minute
= sect
;
87 vcd_inc_msf(mp_vcd_priv_t
* vcd
)
90 vcd
->entry
.data
= &vcd
->entry_data
;
92 TOCADDR(vcd
->entry
).msf
.frame
++;
93 if (TOCADDR(vcd
->entry
).msf
.frame
==75){
94 TOCADDR(vcd
->entry
).msf
.frame
=0;
95 TOCADDR(vcd
->entry
).msf
.second
++;
96 if (TOCADDR(vcd
->entry
).msf
.second
==60){
97 TOCADDR(vcd
->entry
).msf
.second
=0;
98 TOCADDR(vcd
->entry
).msf
.minute
++;
103 static inline unsigned int
104 vcd_get_msf(mp_vcd_priv_t
* vcd
)
107 vcd
->entry
.data
= &vcd
->entry_data
;
109 return TOCADDR(vcd
->entry
).msf
.frame
+
110 (TOCADDR(vcd
->entry
).msf
.second
+
111 TOCADDR(vcd
->entry
).msf
.minute
* 60) * 75 - 150;
115 * \brief read a TOC entry
116 * \param fd device to read from
117 * \param dst buffer to read data into
118 * \param nr track number to read info for
119 * \return 1 on success, 0 on failure
122 read_toc_entry(mp_vcd_priv_t
*vcd
, int nr
)
124 vcd
->entry
.address_format
= CD_MSF_FORMAT
;
126 vcd
->entry
.data_len
= sizeof(struct cd_toc_entry
);
127 vcd
->entry
.data
= &vcd
->entry_data
;
128 vcd
->entry
.starting_track
= nr
;
130 vcd
->entry
.track
= nr
;
132 if (ioctl(vcd
->fd
, READ_TOC
, &vcd
->entry
) == -1) {
133 mp_msg(MSGT_OPEN
,MSGL_ERR
,"read CDROM toc entry: %s\n",strerror(errno
));
140 vcd_seek_to_track(mp_vcd_priv_t
* vcd
, int track
)
142 if (!read_toc_entry(vcd
, track
))
144 return VCD_SECTOR_DATA
* vcd_get_msf(vcd
);
148 vcd_get_track_end(mp_vcd_priv_t
* vcd
, int track
)
150 if (!read_toc_entry(vcd
,
151 track
< vcd
->tochdr
.ending_track
? track
+ 1 : CDROM_LEADOUT
))
153 return VCD_SECTOR_DATA
* vcd_get_msf(vcd
);
156 static mp_vcd_priv_t
*
159 struct ioc_toc_header tochdr
;
161 int i
, last_startsect
;
162 if (ioctl(fd
, CDIOREADTOCHEADER
, &tochdr
) == -1) {
163 mp_msg(MSGT_OPEN
,MSGL_ERR
,"read CDROM toc header: %s\n",strerror(errno
));
166 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VCD_START_TRACK=%d\n", tochdr
.starting_track
);
167 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VCD_END_TRACK=%d\n", tochdr
.ending_track
);
168 vcd
= malloc(sizeof(mp_vcd_priv_t
));
170 vcd
->tochdr
= tochdr
;
171 for (i
= tochdr
.starting_track
; i
<= tochdr
.ending_track
+ 1; i
++) {
172 if (!read_toc_entry(vcd
,
173 i
<= tochdr
.ending_track
? i
: CDROM_LEADOUT
)) {
178 if (i
<= tochdr
.ending_track
)
179 mp_msg(MSGT_OPEN
,MSGL_INFO
,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n",
181 (int)vcd
->entry
.starting_track
,
182 (int)vcd
->entry
.data
->addr_type
,
183 (int)vcd
->entry
.data
->control
,
185 (int)vcd
->entry
.track
,
186 (int)vcd
->entry
.entry
.addr_type
,
187 (int)vcd
->entry
.entry
.control
,
189 (int)vcd
->entry
.address_format
,
190 (int)TOCADDR(vcd
->entry
).msf
.minute
,
191 (int)TOCADDR(vcd
->entry
).msf
.second
,
192 (int)TOCADDR(vcd
->entry
).msf
.frame
195 if (mp_msg_test(MSGT_IDENTIFY
, MSGL_INFO
))
197 int startsect
= vcd_get_msf(vcd
);
198 if (i
> tochdr
.starting_track
)
200 // convert duraion to MSF
201 vcd_set_msf(vcd
, startsect
- last_startsect
);
202 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
203 "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n",
205 TOCADDR(vcd
->entry
).msf
.minute
,
206 TOCADDR(vcd
->entry
).msf
.second
,
207 TOCADDR(vcd
->entry
).msf
.frame
);
209 last_startsect
= startsect
;
216 vcd_read(mp_vcd_priv_t
* vcd
, char *mem
)
220 int lba
= vcd_get_msf(vcd
);
226 memset(&sc
, 0, sizeof(sc
));
228 sc
.cmd
[1] = 5 << 2; // mode2/form2
229 AV_WB32(&sc
.cmd
[2], lba
);
230 AV_WB24(&sc
.cmd
[6], blocks
);
231 sc
.cmd
[9] = 1 << 4; // user data only
232 sc
.cmd
[10] = 0; // no subchannel
234 sc
.databuf
= (caddr_t
) mem
;
235 sc
.datalen
= VCD_SECTOR_DATA
;
236 sc
.senselen
= sizeof(sc
.sense
);
237 sc
.flags
= SCCMD_READ
;
239 rc
= ioctl(vcd
->fd
, SCIOCCOMMAND
, &sc
);
241 mp_msg(MSGT_STREAM
,MSGL_ERR
,"SCIOCCOMMAND: %s\n",strerror(errno
));
244 if (sc
.retsts
|| sc
.error
) {
245 mp_msg(MSGT_STREAM
,MSGL_ERR
,"scsi command failed: status %d error %d\n",
250 if (pread(vcd
->fd
,&vcd
->buf
,VCD_SECTOR_SIZE
,vcd_get_msf(vcd
)*VCD_SECTOR_SIZE
)
251 != VCD_SECTOR_SIZE
) return 0; // EOF?
253 memcpy(mem
,vcd
->buf
.data
,VCD_SECTOR_DATA
);
256 return VCD_SECTOR_DATA
;
259 #endif /* MPLAYER_VCD_READ_FBSD_H */