00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include <cdio/cdda.h>
00027 #include <cdio/paranoia.h>
00028
00029 #include "libavutil/log.h"
00030 #include "libavutil/mem.h"
00031 #include "libavutil/opt.h"
00032
00033 #include "libavformat/avformat.h"
00034 #include "libavformat/internal.h"
00035
00036 typedef struct CDIOContext {
00037 const AVClass *class;
00038 cdrom_drive_t *drive;
00039 cdrom_paranoia_t *paranoia;
00040 int32_t last_sector;
00041
00042
00043 int speed;
00044 int paranoia_mode;
00045 } CDIOContext;
00046
00047 static av_cold int read_header(AVFormatContext *ctx)
00048 {
00049 CDIOContext *s = ctx->priv_data;
00050 AVStream *st;
00051 int ret, i;
00052 char *err = NULL;
00053
00054 if (!(st = avformat_new_stream(ctx, NULL)))
00055 return AVERROR(ENOMEM);
00056 s->drive = cdio_cddap_identify(ctx->filename, CDDA_MESSAGE_LOGIT, &err);
00057 if (!s->drive) {
00058 av_log(ctx, AV_LOG_ERROR, "Could not open drive %s.\n", ctx->filename);
00059 return AVERROR(EINVAL);
00060 }
00061 if (err) {
00062 av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
00063 free(err);
00064 }
00065 if ((ret = cdio_cddap_open(s->drive)) < 0 || !s->drive->opened) {
00066 av_log(ctx, AV_LOG_ERROR, "Could not open disk in drive %s.\n", ctx->filename);
00067 return AVERROR(EINVAL);
00068 }
00069
00070 cdio_cddap_verbose_set(s->drive, CDDA_MESSAGE_LOGIT, CDDA_MESSAGE_LOGIT);
00071 if (s->speed)
00072 cdio_cddap_speed_set(s->drive, s->speed);
00073
00074 s->paranoia = cdio_paranoia_init(s->drive);
00075 if (!s->paranoia) {
00076 av_log(ctx, AV_LOG_ERROR, "Could not init paranoia.\n");
00077 return AVERROR(EINVAL);
00078 }
00079 cdio_paranoia_modeset(s->paranoia, s->paranoia_mode);
00080
00081 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00082 if (s->drive->bigendianp)
00083 st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
00084 else
00085 st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
00086 st->codec->sample_rate = 44100;
00087 st->codec->channels = 2;
00088 if (s->drive->audio_last_sector != CDIO_INVALID_LSN &&
00089 s->drive->audio_first_sector != CDIO_INVALID_LSN)
00090 st->duration = s->drive->audio_last_sector - s->drive->audio_first_sector;
00091 else if (s->drive->tracks)
00092 st->duration = s->drive->disc_toc[s->drive->tracks].dwStartSector;
00093 avpriv_set_pts_info(st, 64, CDIO_CD_FRAMESIZE_RAW, 2*st->codec->channels*st->codec->sample_rate);
00094
00095 for (i = 0; i < s->drive->tracks; i++) {
00096 char title[16];
00097 snprintf(title, sizeof(title), "track %02d", s->drive->disc_toc[i].bTrack);
00098 avpriv_new_chapter(ctx, i, st->time_base, s->drive->disc_toc[i].dwStartSector,
00099 s->drive->disc_toc[i+1].dwStartSector, title);
00100 }
00101
00102 s->last_sector = cdio_cddap_disc_lastsector(s->drive);
00103
00104 return 0;
00105 }
00106
00107 static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
00108 {
00109 CDIOContext *s = ctx->priv_data;
00110 int ret;
00111 uint16_t *buf;
00112 char *err = NULL;
00113
00114 if (ctx->streams[0]->cur_dts > s->last_sector)
00115 return AVERROR_EOF;
00116
00117 buf = cdio_paranoia_read(s->paranoia, NULL);
00118 if (!buf)
00119 return AVERROR_EOF;
00120
00121 if (err = cdio_cddap_errors(s->drive)) {
00122 av_log(ctx, AV_LOG_ERROR, "%s\n", err);
00123 free(err);
00124 err = NULL;
00125 }
00126 if (err = cdio_cddap_messages(s->drive)) {
00127 av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
00128 free(err);
00129 err = NULL;
00130 }
00131
00132 if ((ret = av_new_packet(pkt, CDIO_CD_FRAMESIZE_RAW)) < 0)
00133 return ret;
00134 memcpy(pkt->data, buf, CDIO_CD_FRAMESIZE_RAW);
00135 return 0;
00136 }
00137
00138 static av_cold int read_close(AVFormatContext *ctx)
00139 {
00140 CDIOContext *s = ctx->priv_data;
00141 cdio_paranoia_free(s->paranoia);
00142 cdio_cddap_close(s->drive);
00143 return 0;
00144 }
00145
00146 static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp,
00147 int flags)
00148 {
00149 CDIOContext *s = ctx->priv_data;
00150 AVStream *st = ctx->streams[0];
00151
00152 cdio_paranoia_seek(s->paranoia, timestamp, SEEK_SET);
00153 st->cur_dts = timestamp;
00154 return 0;
00155 }
00156
00157 #define OFFSET(x) offsetof(CDIOContext, x)
00158 #define DEC AV_OPT_FLAG_DECODING_PARAM
00159 static const AVOption options[] = {
00160 { "speed", "Drive reading speed.", OFFSET(speed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
00161 { "paranoia_mode", "Error recovery mode.", OFFSET(paranoia_mode), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, DEC, "paranoia_mode" },
00162 { "verify", "Verify data integrity in overlap area", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_VERIFY }, 0, 0, DEC, "paranoia_mode" },
00163 { "overlap", "Perform overlapped reads.", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_OVERLAP }, 0, 0, DEC, "paranoia_mode" },
00164 { "neverskip", "Do not skip failed reads.", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_NEVERSKIP }, 0, 0, DEC, "paranoia_mode" },
00165 { NULL },
00166 };
00167
00168 static const AVClass libcdio_class = {
00169 .class_name = "libcdio indev",
00170 .item_name = av_default_item_name,
00171 .option = options,
00172 .version = LIBAVUTIL_VERSION_INT,
00173 };
00174
00175 AVInputFormat ff_libcdio_demuxer = {
00176 .name = "libcdio",
00177 .read_header = read_header,
00178 .read_packet = read_packet,
00179 .read_close = read_close,
00180 .read_seek = read_seek,
00181 .priv_data_size = sizeof(CDIOContext),
00182 .flags = AVFMT_NOFILE,
00183 .priv_class = &libcdio_class,
00184 };