3 #include "libavutil/intreadwrite.h"
5 #if defined(__NetBSD__) || defined(__OpenBSD__)
9 #include <sys/scsiio.h>
10 #define TOCADDR(te) ((te).data->addr)
11 #define READ_TOC CDIOREADTOCENTRYS
13 #include <sys/cdrio.h>
14 #define TOCADDR(te) ((te).entry.addr)
15 #define READ_TOC CDIOREADTOCENTRY
18 //=================== VideoCD ==========================
19 #define CDROM_LEADOUT 0xAA
24 uint8_t subheader
[8];
30 typedef struct ioc_read_toc_entry vcd_tocentry
;
32 typedef struct ioc_read_toc_single_entry vcd_tocentry
;
35 typedef struct mp_vcd_priv_st
{
39 struct cd_toc_entry entry_data
;
43 struct ioc_toc_header tochdr
;
47 vcd_set_msf(mp_vcd_priv_t
* vcd
, unsigned int sect
)
50 vcd
->entry
.data
= &vcd
->entry_data
;
53 TOCADDR(vcd
->entry
).msf
.frame
= sect
% 75;
55 TOCADDR(vcd
->entry
).msf
.second
= sect
% 60;
57 TOCADDR(vcd
->entry
).msf
.minute
= sect
;
61 vcd_inc_msf(mp_vcd_priv_t
* vcd
)
64 vcd
->entry
.data
= &vcd
->entry_data
;
66 TOCADDR(vcd
->entry
).msf
.frame
++;
67 if (TOCADDR(vcd
->entry
).msf
.frame
==75){
68 TOCADDR(vcd
->entry
).msf
.frame
=0;
69 TOCADDR(vcd
->entry
).msf
.second
++;
70 if (TOCADDR(vcd
->entry
).msf
.second
==60){
71 TOCADDR(vcd
->entry
).msf
.second
=0;
72 TOCADDR(vcd
->entry
).msf
.minute
++;
77 static inline unsigned int
78 vcd_get_msf(mp_vcd_priv_t
* vcd
)
81 vcd
->entry
.data
= &vcd
->entry_data
;
83 return TOCADDR(vcd
->entry
).msf
.frame
+
84 (TOCADDR(vcd
->entry
).msf
.second
+
85 TOCADDR(vcd
->entry
).msf
.minute
* 60) * 75 - 150;
89 * \brief read a TOC entry
90 * \param fd device to read from
91 * \param dst buffer to read data into
92 * \param nr track number to read info for
93 * \return 1 on success, 0 on failure
96 read_toc_entry(mp_vcd_priv_t
*vcd
, int nr
)
98 vcd
->entry
.address_format
= CD_MSF_FORMAT
;
100 vcd
->entry
.data_len
= sizeof(struct cd_toc_entry
);
101 vcd
->entry
.data
= &vcd
->entry_data
;
102 vcd
->entry
.starting_track
= nr
;
104 vcd
->entry
.track
= nr
;
106 if (ioctl(vcd
->fd
, READ_TOC
, &vcd
->entry
) == -1) {
107 mp_msg(MSGT_OPEN
,MSGL_ERR
,"read CDROM toc entry: %s\n",strerror(errno
));
114 vcd_seek_to_track(mp_vcd_priv_t
* vcd
, int track
)
116 if (!read_toc_entry(vcd
, track
))
118 return VCD_SECTOR_DATA
* vcd_get_msf(vcd
);
122 vcd_get_track_end(mp_vcd_priv_t
* vcd
, int track
)
124 if (!read_toc_entry(vcd
,
125 track
< vcd
->tochdr
.ending_track
? track
+ 1 : CDROM_LEADOUT
))
127 return VCD_SECTOR_DATA
* vcd_get_msf(vcd
);
133 struct ioc_toc_header tochdr
;
135 int i
, last_startsect
;
136 if (ioctl(fd
, CDIOREADTOCHEADER
, &tochdr
) == -1) {
137 mp_msg(MSGT_OPEN
,MSGL_ERR
,"read CDROM toc header: %s\n",strerror(errno
));
140 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VCD_START_TRACK=%d\n", tochdr
.starting_track
);
141 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VCD_END_TRACK=%d\n", tochdr
.ending_track
);
142 vcd
= malloc(sizeof(mp_vcd_priv_t
));
144 vcd
->tochdr
= tochdr
;
145 for (i
= tochdr
.starting_track
; i
<= tochdr
.ending_track
+ 1; i
++) {
146 if (!read_toc_entry(vcd
,
147 i
<= tochdr
.ending_track
? i
: CDROM_LEADOUT
)) {
152 if (i
<= tochdr
.ending_track
)
153 mp_msg(MSGT_OPEN
,MSGL_INFO
,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n",
155 (int)vcd
->entry
.starting_track
,
156 (int)vcd
->entry
.data
->addr_type
,
157 (int)vcd
->entry
.data
->control
,
159 (int)vcd
->entry
.track
,
160 (int)vcd
->entry
.entry
.addr_type
,
161 (int)vcd
->entry
.entry
.control
,
163 (int)vcd
->entry
.address_format
,
164 (int)TOCADDR(vcd
->entry
).msf
.minute
,
165 (int)TOCADDR(vcd
->entry
).msf
.second
,
166 (int)TOCADDR(vcd
->entry
).msf
.frame
169 if (mp_msg_test(MSGT_IDENTIFY
, MSGL_INFO
))
171 int startsect
= vcd_get_msf(vcd
);
172 if (i
> tochdr
.starting_track
)
174 // convert duraion to MSF
175 vcd_set_msf(vcd
, startsect
- last_startsect
);
176 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
177 "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n",
179 TOCADDR(vcd
->entry
).msf
.minute
,
180 TOCADDR(vcd
->entry
).msf
.second
,
181 TOCADDR(vcd
->entry
).msf
.frame
);
183 last_startsect
= startsect
;
190 vcd_read(mp_vcd_priv_t
* vcd
, char *mem
)
194 int lba
= vcd_get_msf(vcd
);
200 memset(&sc
, 0, sizeof(sc
));
202 sc
.cmd
[1] = 5 << 2; // mode2/form2
203 AV_WB32(&sc
.cmd
[2], lba
);
204 AV_WB24(&sc
.cmd
[6], blocks
);
205 sc
.cmd
[9] = 1 << 4; // user data only
206 sc
.cmd
[10] = 0; // no subchannel
208 sc
.databuf
= (caddr_t
) mem
;
210 sc
.senselen
= sizeof(sc
.sense
);
211 sc
.flags
= SCCMD_READ
;
213 rc
= ioctl(vcd
->fd
, SCIOCCOMMAND
, &sc
);
215 mp_msg(MSGT_STREAM
,MSGL_ERR
,"SCIOCCOMMAND: %s\n",strerror(errno
));
218 if (sc
.retsts
|| sc
.error
) {
219 mp_msg(MSGT_STREAM
,MSGL_ERR
,"scsi command failed: status %d error %d\n",
224 if (pread(vcd
->fd
,&vcd
->buf
,VCD_SECTOR_SIZE
,vcd_get_msf(vcd
)*VCD_SECTOR_SIZE
)
225 != VCD_SECTOR_SIZE
) return 0; // EOF?
227 memcpy(mem
,vcd
->buf
.data
,VCD_SECTOR_DATA
);
230 return VCD_SECTOR_DATA
;