Browse code

lavd: add libcdio-paranoia input device for audio CD grabbing

Anton Khirnov authored on 2011/09/14 00:23:06
Showing 6 changed files
... ...
@@ -45,6 +45,7 @@ easier to use. The changes are:
45 45
 - LATM muxer
46 46
 - showinfo filter
47 47
 - split filter
48
+- libcdio-paranoia input device for audio CD grabbing
48 49
 
49 50
 
50 51
 version 0.7:
... ...
@@ -165,6 +165,7 @@ External library support:
165 165
   --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
166 166
   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
167 167
   --enable-libopencv       enable video filtering via libopencv [no]
168
+  --enable-libcdio         enable audio CD grabbing with libcdio
168 169
   --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394
169 170
                            and libraw1394 [no]
170 171
   --enable-libdirac        enable Dirac support via libdirac [no]
... ...
@@ -927,6 +928,7 @@ CONFIG_LIST="
927 927
     h264pred
928 928
     hardcoded_tables
929 929
     huffman
930
+    libcdio
930 931
     libdc1394
931 932
     libdirac
932 933
     libfaac
... ...
@@ -1451,6 +1453,7 @@ bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr
1451 1451
 dv1394_indev_deps="dv1394 dv_demuxer"
1452 1452
 fbdev_indev_deps="linux_fb_h"
1453 1453
 jack_indev_deps="jack_jack_h"
1454
+libcdio_indev_deps="libcdio"
1454 1455
 libdc1394_indev_deps="libdc1394"
1455 1456
 oss_indev_deps_any="soundcard_h sys_soundcard_h"
1456 1457
 oss_outdev_deps_any="soundcard_h sys_soundcard_h"
... ...
@@ -2546,6 +2549,7 @@ die_license_disabled() {
2546 2546
     enabled $1 || { enabled $2 && die "$2 is $1 and --enable-$1 is not specified."; }
2547 2547
 }
2548 2548
 
2549
+die_license_disabled gpl libcdio
2549 2550
 die_license_disabled gpl libx264
2550 2551
 die_license_disabled gpl libxavs
2551 2552
 die_license_disabled gpl libxvid
... ...
@@ -2941,6 +2945,9 @@ enabled jack_indev && check_lib2 jack/jack.h jack_client_open -ljack
2941 2941
 
2942 2942
 enabled_any sndio_indev sndio_outdev && check_lib2 sndio.h sio_open -lsndio
2943 2943
 
2944
+enabled libcdio &&
2945
+    check_lib2 "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open "-lcdio_paranoia -lcdio_cdda -lcdio"
2946
+
2944 2947
 enabled x11grab                         &&
2945 2948
 check_header X11/Xlib.h                 &&
2946 2949
 check_header X11/extensions/XShm.h      &&
... ...
@@ -3146,6 +3153,7 @@ echo "libva enabled             ${vaapi-no}"
3146 3146
 echo "libvdpau enabled          ${vdpau-no}"
3147 3147
 echo "AVISynth enabled          ${avisynth-no}"
3148 3148
 echo "frei0r enabled            ${frei0r-no}"
3149
+echo "libcdio support           ${libcdio-no}"
3149 3150
 echo "libdc1394 support         ${libdc1394-no}"
3150 3151
 echo "libdirac enabled          ${libdirac-no}"
3151 3152
 echo "libfaac enabled           ${libfaac-no}"
... ...
@@ -24,6 +24,7 @@ OBJS-$(CONFIG_VFWCAP_INDEV)              += vfwcap.o
24 24
 OBJS-$(CONFIG_X11_GRAB_DEVICE_INDEV)     += x11grab.o
25 25
 
26 26
 # external libraries
27
+OBJS-$(CONFIG_LIBCDIO_INDEV)             += libcdio.o
27 28
 OBJS-$(CONFIG_LIBDC1394_INDEV)           += libdc1394.o
28 29
 
29 30
 SKIPHEADERS-$(HAVE_ALSA_ASOUNDLIB_H)     += alsa-audio.h
... ...
@@ -54,5 +54,6 @@ void avdevice_register_all(void)
54 54
     REGISTER_INDEV    (X11_GRAB_DEVICE, x11_grab_device);
55 55
 
56 56
     /* external libraries */
57
+    REGISTER_INDEV    (LIBCDIO, libcdio);
57 58
     REGISTER_INDEV    (LIBDC1394, libdc1394);
58 59
 }
... ...
@@ -22,7 +22,7 @@
22 22
 #include "libavutil/avutil.h"
23 23
 
24 24
 #define LIBAVDEVICE_VERSION_MAJOR 53
25
-#define LIBAVDEVICE_VERSION_MINOR  0
25
+#define LIBAVDEVICE_VERSION_MINOR  1
26 26
 #define LIBAVDEVICE_VERSION_MICRO  0
27 27
 
28 28
 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
29 29
new file mode 100644
... ...
@@ -0,0 +1,186 @@
0
+/*
1
+ * Copyright (c) 2011 Anton Khirnov <anton@khirnov.net>
2
+ *
3
+ * This file is part of Libav.
4
+ *
5
+ * Libav is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * Libav is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with Libav; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+/**
21
+ * @file
22
+ * libcdio CD grabbing
23
+ */
24
+
25
+#include <cdio/cdda.h>
26
+#include <cdio/paranoia.h>
27
+
28
+#include "libavutil/log.h"
29
+#include "libavutil/mem.h"
30
+#include "libavutil/opt.h"
31
+
32
+#include "libavformat/avformat.h"
33
+#include "libavformat/internal.h"
34
+
35
+/* cdio returns some malloced strings that need to be free()d */
36
+#undef free
37
+
38
+typedef struct CDIOContext {
39
+    cdrom_drive_t       *drive;
40
+    cdrom_paranoia_t *paranoia;
41
+    int32_t last_sector;
42
+
43
+    /* private options */
44
+    int speed;
45
+    int paranoia_mode;
46
+} CDIOContext;
47
+
48
+static av_cold int read_header(AVFormatContext *ctx, AVFormatParameters *ap)
49
+{
50
+    CDIOContext *s = ctx->priv_data;
51
+    AVStream *st;
52
+    int ret, i;
53
+    char *err = NULL;
54
+
55
+    if (!(st = av_new_stream(ctx, 0)))
56
+        return AVERROR(ENOMEM);
57
+    s->drive = cdio_cddap_identify(ctx->filename, CDDA_MESSAGE_LOGIT, &err);
58
+    if (!s->drive) {
59
+        av_log(ctx, AV_LOG_ERROR, "Could not open drive %s.\n", ctx->filename);
60
+        return AVERROR(EINVAL);
61
+    }
62
+    if (err) {
63
+        av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
64
+        free(err);
65
+    }
66
+    if ((ret = cdio_cddap_open(s->drive)) < 0 || !s->drive->opened) {
67
+        av_log(ctx, AV_LOG_ERROR, "Could not open disk in drive %s.\n", ctx->filename);
68
+        return AVERROR(EINVAL);
69
+    }
70
+
71
+    cdio_cddap_verbose_set(s->drive, CDDA_MESSAGE_LOGIT, CDDA_MESSAGE_LOGIT);
72
+    if (s->speed)
73
+        cdio_cddap_speed_set(s->drive, s->speed);
74
+
75
+    s->paranoia = cdio_paranoia_init(s->drive);
76
+    if (!s->paranoia) {
77
+        av_log(ctx, AV_LOG_ERROR, "Could not init paranoia.\n");
78
+        return AVERROR(EINVAL);
79
+    }
80
+    cdio_paranoia_modeset(s->paranoia, s->paranoia_mode);
81
+
82
+    st->codec->codec_type      = AVMEDIA_TYPE_AUDIO;
83
+    if (s->drive->bigendianp)
84
+        st->codec->codec_id    = CODEC_ID_PCM_S16BE;
85
+    else
86
+        st->codec->codec_id    = CODEC_ID_PCM_S16LE;
87
+    st->codec->sample_rate     = 44100;
88
+    st->codec->channels        = 2;
89
+    if (s->drive->audio_last_sector != CDIO_INVALID_LSN &&
90
+        s->drive->audio_first_sector != CDIO_INVALID_LSN)
91
+        st->duration           = s->drive->audio_last_sector - s->drive->audio_first_sector;
92
+    else if (s->drive->tracks)
93
+        st->duration = s->drive->disc_toc[s->drive->tracks].dwStartSector;
94
+    av_set_pts_info(st, 64, CDIO_CD_FRAMESIZE_RAW, 2*st->codec->channels*st->codec->sample_rate);
95
+
96
+    for (i = 0; i < s->drive->tracks; i++) {
97
+        char title[16];
98
+        snprintf(title, sizeof(title), "track %02d", s->drive->disc_toc[i].bTrack);
99
+        ff_new_chapter(ctx, i, st->time_base, s->drive->disc_toc[i].dwStartSector,
100
+                       s->drive->disc_toc[i+1].dwStartSector, title);
101
+    }
102
+
103
+    s->last_sector = cdio_cddap_disc_lastsector(s->drive);
104
+
105
+    return 0;
106
+}
107
+
108
+static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
109
+{
110
+    CDIOContext *s = ctx->priv_data;
111
+    int ret;
112
+    uint16_t *buf;
113
+    char *err = NULL;
114
+
115
+    if (ctx->streams[0]->cur_dts > s->last_sector)
116
+        return AVERROR_EOF;
117
+
118
+    buf = cdio_paranoia_read(s->paranoia, NULL);
119
+    if (!buf)
120
+        return AVERROR_EOF;
121
+
122
+    if (err = cdio_cddap_errors(s->drive)) {
123
+        av_log(ctx, AV_LOG_ERROR, "%s\n", err);
124
+        free(err);
125
+        err = NULL;
126
+    }
127
+    if (err = cdio_cddap_messages(s->drive)) {
128
+        av_log(ctx, AV_LOG_VERBOSE, "%s\n", err);
129
+        free(err);
130
+        err = NULL;
131
+    }
132
+
133
+    if ((ret = av_new_packet(pkt, CDIO_CD_FRAMESIZE_RAW)) < 0)
134
+        return ret;
135
+    memcpy(pkt->data, buf, CDIO_CD_FRAMESIZE_RAW);
136
+    return 0;
137
+}
138
+
139
+static av_cold int read_close(AVFormatContext *ctx)
140
+{
141
+    CDIOContext *s = ctx->priv_data;
142
+    cdio_paranoia_free(s->paranoia);
143
+    cdio_cddap_close(s->drive);
144
+    return 0;
145
+}
146
+
147
+static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp,
148
+                     int flags)
149
+{
150
+    CDIOContext *s = ctx->priv_data;
151
+    AVStream *st = ctx->streams[0];
152
+
153
+    cdio_paranoia_seek(s->paranoia, timestamp, SEEK_SET);
154
+    st->cur_dts = timestamp;
155
+    return 0;
156
+}
157
+
158
+#define OFFSET(x) offsetof(CDIOContext, x)
159
+#define DEC AV_OPT_FLAG_DECODING_PARAM
160
+static const AVOption options[] = {
161
+    { "speed",              "Drive reading speed.", OFFSET(speed),         FF_OPT_TYPE_INT,   { 0 }, 0,       INT_MAX, DEC },
162
+    { "paranoia_mode",      "Error recovery mode.", OFFSET(paranoia_mode), FF_OPT_TYPE_FLAGS, { 0 }, INT_MIN, INT_MAX, DEC, "paranoia_mode" },
163
+        { "verify",         "Verify data integrity in overlap area", 0,    FF_OPT_TYPE_CONST, { PARANOIA_MODE_VERIFY },    0, 0, DEC, "paranoia_mode" },
164
+        { "overlap",        "Perform overlapped reads.",             0,    FF_OPT_TYPE_CONST, { PARANOIA_MODE_OVERLAP },   0, 0, DEC, "paranoia_mode" },
165
+        { "neverskip",      "Do not skip failed reads.",             0,    FF_OPT_TYPE_CONST, { PARANOIA_MODE_NEVERSKIP }, 0, 0, DEC, "paranoia_mode" },
166
+    { NULL },
167
+};
168
+
169
+static const AVClass libcdio_class = {
170
+    .class_name = "libcdio indev",
171
+    .item_name  = av_default_item_name,
172
+    .option     = options,
173
+    .version    = LIBAVUTIL_VERSION_INT,
174
+};
175
+
176
+AVInputFormat ff_libcdio_demuxer = {
177
+    .name           = "libcdio",
178
+    .read_header    = read_header,
179
+    .read_packet    = read_packet,
180
+    .read_close     = read_close,
181
+    .read_seek      = read_seek,
182
+    .priv_data_size = sizeof(CDIOContext),
183
+    .flags          = AVFMT_NOFILE,
184
+    .priv_class     = &libcdio_class,
185
+};