Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52868 views
1
/*
2
* Copyright (c) 2011 Anton Khirnov <[email protected]>
3
*
4
* This file is part of FFmpeg.
5
*
6
* FFmpeg is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* FFmpeg is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with FFmpeg; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
/**
22
* @file
23
* libcdio CD grabbing
24
*/
25
26
#include "config.h"
27
28
#if HAVE_CDIO_PARANOIA_H
29
#include <cdio/cdda.h>
30
#include <cdio/paranoia.h>
31
#elif HAVE_CDIO_PARANOIA_PARANOIA_H
32
#include <cdio/paranoia/cdda.h>
33
#include <cdio/paranoia/paranoia.h>
34
#endif
35
36
#include "libavutil/log.h"
37
#include "libavutil/mem.h"
38
#include "libavutil/opt.h"
39
40
#include "libavformat/avformat.h"
41
#include "libavformat/internal.h"
42
43
typedef struct CDIOContext {
44
const AVClass *class;
45
cdrom_drive_t *drive;
46
cdrom_paranoia_t *paranoia;
47
int32_t last_sector;
48
49
/* private options */
50
int speed;
51
int paranoia_mode;
52
} CDIOContext;
53
54
static av_cold int read_header(AVFormatContext *ctx)
55
{
56
CDIOContext *s = ctx->priv_data;
57
AVStream *st;
58
int ret, i;
59
char *err = NULL;
60
61
if (!(st = avformat_new_stream(ctx, NULL)))
62
return AVERROR(ENOMEM);
63
s->drive = cdio_cddap_identify(ctx->filename, CDDA_MESSAGE_LOGIT, &err);
64
if (!s->drive) {
65
av_log(ctx, AV_LOG_ERROR, "Could not open drive %s.\n", ctx->filename);
66
return AVERROR(EINVAL);
67
}
68
if (err) {
69
av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
70
free(err);
71
}
72
if ((ret = cdio_cddap_open(s->drive)) < 0 || !s->drive->opened) {
73
av_log(ctx, AV_LOG_ERROR, "Could not open disk in drive %s.\n", ctx->filename);
74
return AVERROR(EINVAL);
75
}
76
77
cdio_cddap_verbose_set(s->drive, CDDA_MESSAGE_LOGIT, CDDA_MESSAGE_LOGIT);
78
if (s->speed)
79
cdio_cddap_speed_set(s->drive, s->speed);
80
81
s->paranoia = cdio_paranoia_init(s->drive);
82
if (!s->paranoia) {
83
av_log(ctx, AV_LOG_ERROR, "Could not init paranoia.\n");
84
return AVERROR(EINVAL);
85
}
86
cdio_paranoia_modeset(s->paranoia, s->paranoia_mode);
87
88
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
89
if (s->drive->bigendianp)
90
st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
91
else
92
st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
93
st->codec->sample_rate = 44100;
94
st->codec->channels = 2;
95
if (s->drive->audio_last_sector != CDIO_INVALID_LSN &&
96
s->drive->audio_first_sector != CDIO_INVALID_LSN)
97
st->duration = s->drive->audio_last_sector - s->drive->audio_first_sector;
98
else if (s->drive->tracks)
99
st->duration = s->drive->disc_toc[s->drive->tracks].dwStartSector;
100
avpriv_set_pts_info(st, 64, CDIO_CD_FRAMESIZE_RAW, 2*st->codec->channels*st->codec->sample_rate);
101
102
for (i = 0; i < s->drive->tracks; i++) {
103
char title[16];
104
snprintf(title, sizeof(title), "track %02d", s->drive->disc_toc[i].bTrack);
105
avpriv_new_chapter(ctx, i, st->time_base, s->drive->disc_toc[i].dwStartSector,
106
s->drive->disc_toc[i+1].dwStartSector, title);
107
}
108
109
s->last_sector = cdio_cddap_disc_lastsector(s->drive);
110
111
return 0;
112
}
113
114
static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
115
{
116
CDIOContext *s = ctx->priv_data;
117
int ret;
118
uint16_t *buf;
119
char *err = NULL;
120
121
if (ctx->streams[0]->cur_dts > s->last_sector)
122
return AVERROR_EOF;
123
124
buf = cdio_paranoia_read(s->paranoia, NULL);
125
if (!buf)
126
return AVERROR_EOF;
127
128
if (err = cdio_cddap_errors(s->drive)) {
129
av_log(ctx, AV_LOG_ERROR, "%s\n", err);
130
free(err);
131
err = NULL;
132
}
133
if (err = cdio_cddap_messages(s->drive)) {
134
av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
135
free(err);
136
err = NULL;
137
}
138
139
if ((ret = av_new_packet(pkt, CDIO_CD_FRAMESIZE_RAW)) < 0)
140
return ret;
141
memcpy(pkt->data, buf, CDIO_CD_FRAMESIZE_RAW);
142
return 0;
143
}
144
145
static av_cold int read_close(AVFormatContext *ctx)
146
{
147
CDIOContext *s = ctx->priv_data;
148
cdio_paranoia_free(s->paranoia);
149
cdio_cddap_close(s->drive);
150
return 0;
151
}
152
153
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp,
154
int flags)
155
{
156
CDIOContext *s = ctx->priv_data;
157
AVStream *st = ctx->streams[0];
158
159
cdio_paranoia_seek(s->paranoia, timestamp, SEEK_SET);
160
st->cur_dts = timestamp;
161
return 0;
162
}
163
164
#define OFFSET(x) offsetof(CDIOContext, x)
165
#define DEC AV_OPT_FLAG_DECODING_PARAM
166
static const AVOption options[] = {
167
{ "speed", "set drive reading speed", OFFSET(speed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
168
{ "paranoia_mode", "set error recovery mode", OFFSET(paranoia_mode), AV_OPT_TYPE_FLAGS, { .i64 = PARANOIA_MODE_DISABLE }, INT_MIN, INT_MAX, DEC, "paranoia_mode" },
169
{ "disable", "apply no fixups", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_DISABLE }, 0, 0, DEC, "paranoia_mode" },
170
{ "verify", "verify data integrity in overlap area", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_VERIFY }, 0, 0, DEC, "paranoia_mode" },
171
{ "overlap", "perform overlapped reads", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_OVERLAP }, 0, 0, DEC, "paranoia_mode" },
172
{ "neverskip", "do not skip failed reads", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_NEVERSKIP }, 0, 0, DEC, "paranoia_mode" },
173
{ "full", "apply all recovery modes", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_FULL }, 0, 0, DEC, "paranoia_mode" },
174
{ NULL },
175
};
176
177
static const AVClass libcdio_class = {
178
.class_name = "libcdio indev",
179
.item_name = av_default_item_name,
180
.option = options,
181
.version = LIBAVUTIL_VERSION_INT,
182
.category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
183
};
184
185
AVInputFormat ff_libcdio_demuxer = {
186
.name = "libcdio",
187
.read_header = read_header,
188
.read_packet = read_packet,
189
.read_close = read_close,
190
.read_seek = read_seek,
191
.priv_data_size = sizeof(CDIOContext),
192
.flags = AVFMT_NOFILE,
193
.priv_class = &libcdio_class,
194
};
195
196