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.
20 #include <cdio/cdda.h>
21 #include <cdio/paranoia.h>
22 #include <cdio/cdio.h>
33 #include "libavutil/common.h"
35 #include "libmpdemux/demuxer.h"
41 extern char *cdrom_device
;
45 cdrom_paranoia_t
*cdp
;
52 static struct cdda_params
{
67 #define ST_OFF(f) M_ST_OFF(struct cdda_params, f)
68 static const m_option_t cdda_params_fields
[] = {
69 {"speed", ST_OFF(speed
), CONF_TYPE_INT
, M_OPT_RANGE
, 0, 100, NULL
},
70 {"paranoia", ST_OFF(paranoia_mode
), CONF_TYPE_INT
, M_OPT_RANGE
, 0, 2,
72 {"generic-dev", ST_OFF(generic_dev
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
73 {"sector-size", ST_OFF(sector_size
), CONF_TYPE_INT
, M_OPT_RANGE
, 1, 100,
75 {"overlap", ST_OFF(search_overlap
), CONF_TYPE_INT
, M_OPT_RANGE
, -1, 75,
77 {"toc-bias", ST_OFF(toc_bias
), CONF_TYPE_INT
, 0, 0, 0, NULL
},
78 {"toc-offset", ST_OFF(toc_offset
), CONF_TYPE_INT
, 0, 0, 0, NULL
},
79 {"noskip", ST_OFF(no_skip
), CONF_TYPE_FLAG
, 0, 0, 1, NULL
},
80 {"skip", ST_OFF(no_skip
), CONF_TYPE_FLAG
, 0, 1, 0, NULL
},
81 {"device", ST_OFF(device
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
82 {"span", ST_OFF(span
), CONF_TYPE_OBJ_PARAMS
, 0, 0, 0,
83 (void *)&m_span_params_def
},
85 {"hostname", ST_OFF(span
), CONF_TYPE_OBJ_PARAMS
, 0, 0, 0,
86 (void *)&m_span_params_def
},
87 {"port", ST_OFF(speed
), CONF_TYPE_INT
, M_OPT_RANGE
, 1, 100, NULL
},
88 {"filename", ST_OFF(device
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
91 static const struct m_struct_st stream_opts
= {
93 sizeof(struct cdda_params
),
98 /// We keep these options but now they set the defaults
99 const m_option_t cdda_opts
[] = {
100 {"speed", &cdda_dflts
.speed
, CONF_TYPE_INT
, M_OPT_RANGE
, 1, 100, NULL
},
101 {"paranoia", &cdda_dflts
.paranoia_mode
, CONF_TYPE_INT
, M_OPT_RANGE
, 0, 2,
103 {"generic-dev", &cdda_dflts
.generic_dev
, CONF_TYPE_STRING
, 0, 0, 0, NULL
},
104 {"sector-size", &cdda_dflts
.sector_size
, CONF_TYPE_INT
, M_OPT_RANGE
, 1,
106 {"overlap", &cdda_dflts
.search_overlap
, CONF_TYPE_INT
, M_OPT_RANGE
, 0, 75,
108 {"toc-bias", &cdda_dflts
.toc_bias
, CONF_TYPE_INT
, 0, 0, 0, NULL
},
109 {"toc-offset", &cdda_dflts
.toc_offset
, CONF_TYPE_INT
, 0, 0, 0, NULL
},
110 {"noskip", &cdda_dflts
.no_skip
, CONF_TYPE_FLAG
, 0, 0, 1, NULL
},
111 {"skip", &cdda_dflts
.no_skip
, CONF_TYPE_FLAG
, 0, 1, 0, NULL
},
112 {"device", &cdda_dflts
.device
, CONF_TYPE_STRING
, 0, 0, 0, NULL
},
113 {"span", &cdda_dflts
.span
, CONF_TYPE_OBJ_PARAMS
, 0, 0, 0,
114 (void *)&m_span_params_def
},
115 {NULL
, NULL
, 0, 0, 0, 0, NULL
}
118 static const char *cdtext_name
[] = {
119 [CDTEXT_ARRANGER
] = "Arranger",
120 [CDTEXT_COMPOSER
] = "Composer",
121 [CDTEXT_MESSAGE
] = "Message",
122 [CDTEXT_ISRC
] = "ISRC",
123 [CDTEXT_PERFORMER
] = "Performer",
124 [CDTEXT_SONGWRITER
] = "Songwriter",
125 [CDTEXT_TITLE
] = "Title",
126 [CDTEXT_UPC_EAN
] = "UPC_EAN",
129 static bool print_cdtext(stream_t
*s
, int track
)
131 cdda_priv
* p
= (cdda_priv
*)s
->priv
;
132 cdtext_t
*text
= cdio_get_cdtext(p
->cd
->p_cdio
, track
);
134 mp_msg(MSGT_SEEK
, MSGL_INFO
, "CD-Text (%s):\n", track
? "track" : "CD");
135 for (int i
= 0; i
< sizeof(cdtext_name
) / sizeof(cdtext_name
[0]); i
++) {
136 const char *name
= cdtext_name
[i
];
137 const char *value
= cdtext_get_const(i
, text
);
139 mp_msg(MSGT_SEEK
, MSGL_INFO
, " %s: '%s'\n", name
, value
);
146 static void print_track_info(stream_t
*s
, int track
)
148 cdda_priv
* p
= (cdda_priv
*)s
->priv
;
149 cd_track_t
*cd_track
= cd_info_get_track(p
->cd_info
, track
);
150 if( cd_track
!=NULL
) {
151 mp_msg(MSGT_SEEK
, MSGL_INFO
, "\n%s\n", cd_track
->name
);
152 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_CDDA_TRACK=%d\n",
155 if (print_cdtext(s
, track
)) {
156 // hack for term OSD overwriting the last line of CDTEXT
157 mp_msg(MSGT_SEEK
, MSGL_INFO
, "\n");
161 static void cdparanoia_callback(long int inpos
, paranoia_cb_mode_t function
)
165 static int fill_buffer(stream_t
*s
, char *buffer
, int max_len
)
167 cdda_priv
*p
= (cdda_priv
*)s
->priv
;
171 if ((p
->sector
< p
->start_sector
) || (p
->sector
> p
->end_sector
)) {
176 buf
= paranoia_read(p
->cdp
, cdparanoia_callback
);
181 for (i
= 0; i
< CDIO_CD_FRAMESIZE_RAW
/ 2; i
++)
182 buf
[i
] = le2me_16(buf
[i
]);
186 memcpy(buffer
, buf
, CDIO_CD_FRAMESIZE_RAW
);
188 for (i
= 0; i
< p
->cd
->tracks
; i
++) {
189 if (p
->cd
->disc_toc
[i
].dwStartSector
== p
->sector
- 1) {
190 print_track_info(s
, i
+ 1);
195 return CDIO_CD_FRAMESIZE_RAW
;
198 static int seek(stream_t
*s
, off_t newpos
)
200 cdda_priv
*p
= (cdda_priv
*)s
->priv
;
202 int current_track
= 0, seeked_track
= 0;
203 int seek_to_track
= 0;
207 sec
= s
->pos
/ CDIO_CD_FRAMESIZE_RAW
;
208 if (s
->pos
< 0 || sec
> p
->end_sector
) {
210 p
->sector
= p
->end_sector
+ 1;
214 for (i
= 0; i
< p
->cd
->tracks
; i
++) {
215 if (p
->sector
>= p
->cd
->disc_toc
[i
].dwStartSector
216 && p
->sector
< p
->cd
->disc_toc
[i
+ 1].dwStartSector
)
218 if (sec
>= p
->cd
->disc_toc
[i
].dwStartSector
219 && sec
< p
->cd
->disc_toc
[i
+ 1].dwStartSector
)
222 seek_to_track
= sec
== p
->cd
->disc_toc
[i
].dwStartSector
;
225 if (current_track
!= seeked_track
&& !seek_to_track
)
226 print_track_info(s
, seeked_track
+ 1);
230 paranoia_seek(p
->cdp
, sec
, SEEK_SET
);
234 static void close_cdda(stream_t
*s
)
236 cdda_priv
*p
= (cdda_priv
*)s
->priv
;
237 paranoia_free(p
->cdp
);
239 cd_info_free(p
->cd_info
);
243 static int get_track_by_sector(cdda_priv
*p
, unsigned int sector
)
246 for (i
= p
->cd
->tracks
; i
>= 0; --i
)
247 if (p
->cd
->disc_toc
[i
].dwStartSector
<= sector
)
252 static int control(stream_t
*stream
, int cmd
, void *arg
)
254 cdda_priv
*p
= stream
->priv
;
256 case STREAM_CTRL_GET_NUM_CHAPTERS
:
258 int start_track
= get_track_by_sector(p
, p
->start_sector
);
259 int end_track
= get_track_by_sector(p
, p
->end_sector
);
260 if (start_track
== -1 || end_track
== -1)
262 *(unsigned int *)arg
= end_track
+ 1 - start_track
;
265 case STREAM_CTRL_SEEK_TO_CHAPTER
:
268 unsigned int track
= *(unsigned int *)arg
;
269 int start_track
= get_track_by_sector(p
, p
->start_sector
);
270 int end_track
= get_track_by_sector(p
, p
->end_sector
);
272 if (start_track
== -1 || end_track
== -1)
274 track
+= start_track
;
275 if (track
> end_track
) {
276 seek(stream
, (p
->end_sector
+ 1) * CDIO_CD_FRAMESIZE_RAW
);
277 // seeking beyond EOF should not be an error,
278 // the cache cannot handle changing stream pos and
282 seek_sector
= track
<= 0 ? p
->start_sector
283 : p
->cd
->disc_toc
[track
].dwStartSector
;
284 r
= seek(stream
, seek_sector
* CDIO_CD_FRAMESIZE_RAW
);
289 case STREAM_CTRL_GET_CURRENT_CHAPTER
:
291 int start_track
= get_track_by_sector(p
, p
->start_sector
);
292 int cur_track
= get_track_by_sector(p
, p
->sector
);
293 if (start_track
== -1 || cur_track
== -1)
295 *(unsigned int *)arg
= cur_track
- start_track
;
299 return STREAM_UNSUPPORTED
;
302 static int open_cdda(stream_t
*st
, int m
, void *opts
, int *file_format
)
304 struct cdda_params
*p
= (struct cdda_params
*)opts
;
305 int mode
= p
->paranoia_mode
;
306 int offset
= p
->toc_offset
;
307 cdrom_drive_t
*cdd
= NULL
;
309 cd_info_t
*cd_info
, *cddb_info
= NULL
;
310 unsigned int audiolen
= 0;
313 char *xmcd_file
= NULL
;
315 if (m
!= STREAM_READ
) {
316 m_struct_free(&stream_opts
, opts
);
317 return STREAM_UNSUPPORTED
;
322 p
->device
= talloc_strdup(NULL
, cdrom_device
);
324 p
->device
= talloc_strdup(NULL
, DEFAULT_CDROM_DEVICE
);
328 // cdd_identify returns -1 if it cannot read the TOC,
329 // in which case there is no point in calling cddb_resolve
330 if (cdd_identify(p
->device
) >= 0 && strncmp(st
->url
, "cddb", 4) == 0) {
331 i
= cddb_resolve(p
->device
, &xmcd_file
);
333 cddb_info
= cddb_parse_xmcd(xmcd_file
);
339 #if defined(__NetBSD__)
340 cdd
= cdda_identify_scsi(p
->device
, p
->device
, 0, NULL
);
342 cdd
= cdda_identify(p
->device
, 0, NULL
);
346 mp_tmsg(MSGT_OPEN
, MSGL_ERR
, "Can't open CDDA device.\n");
347 m_struct_free(&stream_opts
, opts
);
352 cdda_verbose_set(cdd
, CDDA_MESSAGE_FORGETIT
, CDDA_MESSAGE_FORGETIT
);
355 cdd
->nsectors
= p
->sector_size
;
357 if (cdda_open(cdd
) != 0) {
358 mp_tmsg(MSGT_OPEN
, MSGL_ERR
, "Can't open disc.\n");
360 m_struct_free(&stream_opts
, opts
);
365 cd_info
= cd_info_new();
366 mp_tmsg(MSGT_OPEN
, MSGL_INFO
, "Found audio CD with %d tracks.\n",
367 (int)cdda_tracks(cdd
));
368 for (i
= 0; i
< cdd
->tracks
; i
++) {
370 long sec
= cdda_track_firstsector(cdd
, i
+ 1);
371 long off
= cdda_track_lastsector(cdd
, i
+ 1) - sec
+ 1;
373 sprintf(track_name
, "Track %d", i
+ 1);
374 cd_info_add_track(cd_info
, track_name
, i
+ 1,
375 (unsigned int)(off
/ (60 * 75)),
376 (unsigned int)((off
/ 75) % 60),
377 (unsigned int)(off
% 75), sec
, off
);
380 cd_info
->min
= (unsigned int)(audiolen
/ (60 * 75));
381 cd_info
->sec
= (unsigned int)((audiolen
/ 75) % 60);
382 cd_info
->msec
= (unsigned int)(audiolen
% 75);
384 priv
= malloc(sizeof(cdda_priv
));
385 memset(priv
, 0, sizeof(cdda_priv
));
387 priv
->cd_info
= cd_info
;
390 offset
-= cdda_track_firstsector(cdd
, 1);
394 for (i
= 0; i
< cdd
->tracks
+ 1; i
++)
395 cdd
->disc_toc
[i
].dwStartSector
+= offset
;
399 cdda_speed_set(cdd
, p
->speed
);
401 last_track
= cdda_tracks(cdd
);
402 if (p
->span
.start
> last_track
)
403 p
->span
.start
= last_track
;
404 if (p
->span
.end
< p
->span
.start
)
405 p
->span
.end
= p
->span
.start
;
406 if (p
->span
.end
> last_track
)
407 p
->span
.end
= last_track
;
409 priv
->start_sector
= cdda_track_firstsector(cdd
, p
->span
.start
);
411 priv
->start_sector
= cdda_disc_firstsector(cdd
);
414 priv
->end_sector
= cdda_track_lastsector(cdd
, p
->span
.end
);
416 priv
->end_sector
= cdda_disc_lastsector(cdd
);
418 priv
->cdp
= paranoia_init(cdd
);
419 if (priv
->cdp
== NULL
) {
422 cd_info_free(cd_info
);
423 m_struct_free(&stream_opts
, opts
);
429 mode
= PARANOIA_MODE_DISABLE
;
431 mode
= PARANOIA_MODE_OVERLAP
;
433 mode
= PARANOIA_MODE_FULL
;
436 mode
|= PARANOIA_MODE_NEVERSKIP
;
438 mode
&= ~PARANOIA_MODE_NEVERSKIP
;
440 if (p
->search_overlap
> 0)
441 mode
|= PARANOIA_MODE_OVERLAP
;
442 else if (p
->search_overlap
== 0)
443 mode
&= ~PARANOIA_MODE_OVERLAP
;
445 paranoia_modeset(priv
->cdp
, mode
);
447 if (p
->search_overlap
> 0)
448 paranoia_overlapset(priv
->cdp
, p
->search_overlap
);
450 paranoia_seek(priv
->cdp
, priv
->start_sector
, SEEK_SET
);
451 priv
->sector
= priv
->start_sector
;
455 cd_info_free(cd_info
);
456 priv
->cd_info
= cddb_info
;
457 cd_info_debug(cddb_info
);
462 st
->start_pos
= priv
->start_sector
* CDIO_CD_FRAMESIZE_RAW
;
463 st
->end_pos
= (priv
->end_sector
+ 1) * CDIO_CD_FRAMESIZE_RAW
;
464 st
->type
= STREAMTYPE_CDDA
;
465 st
->sector_size
= CDIO_CD_FRAMESIZE_RAW
;
467 st
->fill_buffer
= fill_buffer
;
469 st
->control
= control
;
470 st
->close
= close_cdda
;
472 *file_format
= DEMUXER_TYPE_RAWAUDIO
;
474 m_struct_free(&stream_opts
, opts
);
481 const stream_info_t stream_info_cdda
= {