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