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