From patchwork Wed Jan 5 14:42:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lucien Murray-Pitts X-Patchwork-Id: 33088 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:cd86:0:0:0:0:0 with SMTP id d128csp787487iog; Wed, 5 Jan 2022 06:43:01 -0800 (PST) X-Google-Smtp-Source: ABdhPJy9fkVi3sIYtWsUARU5QGK2dz1xMJOW0vcDkeind0Lx52vmCet9qQsa6F5yiYzqSSZrzrZE X-Received: by 2002:a17:907:9808:: with SMTP id ji8mr43560614ejc.665.1641393780827; Wed, 05 Jan 2022 06:43:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1641393780; cv=none; d=google.com; s=arc-20160816; b=n0eFsMnf/H4TleRl+cdW4DPCWDS3MwBaGFvugwBiizIgYliVKon8mnaVQ4SoYym9s0 o7tBEeMlWF+xQCJYTSYw4l/bon1J1YKgUP6sSEtxWv0uLsyWIXGGKdJtlmakuZtMqFeH hvHexfi6ogxWBc7ovTSv02Al+bv9KAFZUYcqCOQSZXUMefOM8sOhct8Woy6b5oXw8bmf kIC8EdfbgdtD9zqRtqbRB8PH7g3Pfjr3faq1RR8XO6WgtyCe8uJ4oYhi0BP+Iq9Dlj/R svnbH0KzpBFfCfoeQC59CUC0hWRrQtfZg71+wr2Qv5n1nlBWKbRw1jeyF1dYVdBgCVTW wG+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:content-disposition:from:to:content-language :user-agent:mime-version:date:message-id:dkim-signature:delivered-to; bh=vXGS3anW/kF7fpYtETCQSk5LZiKY/BC9aOGiquO2HGQ=; b=Pib00Zz4IeBatp5rEgcYFSfyUn06/APFqLLP6SJa4j9R5XKhAmUFB6BdFz4gN/8Qkd 5etPy2y0q2yh8dtyl1vZJVkGGxlzJ1w7fJ3/eJkxRtsxkIU4tvHIkgmITCHFzVU1R09v PXn9PeBB0/X29YnLK04mD4sKbIfSyiDYbX00hbYDK1KHzAxg6hMmQZ9Iwo8iktvV+Jew qWHetwmIwnxfvZZD8Fpjm4qLV0iUJEa+O4QqiKu1FhgviOqTBSsnRxe1aFjCoIBTQJf9 TeHoV+VmY1Qpe2ivzpLZZZJAlxJOQ6wODumd5CUH7nXe4CHulVN6EXuUS59VS0DwojVS owtQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=QOg1yROR; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id cz8si290397edb.109.2022.01.05.06.43.00; Wed, 05 Jan 2022 06:43:00 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=QOg1yROR; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 656F068A71A; Wed, 5 Jan 2022 16:42:57 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pj1-f41.google.com (mail-pj1-f41.google.com [209.85.216.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 88F2268A71A for ; Wed, 5 Jan 2022 16:42:50 +0200 (EET) Received: by mail-pj1-f41.google.com with SMTP id r16-20020a17090a0ad000b001b276aa3aabso4403410pje.0 for ; Wed, 05 Jan 2022 06:42:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:date:mime-version:user-agent:content-language:to:from :subject; bh=joe/VHjM3vFzOdXNr0FRiV3E7mTaokFEsnNbfeMiCHQ=; b=QOg1yRORFomyPtf0gfDiBDuX/iDG5Vps48ERV8pf064KNcLn29QbQvW9dYhP6cmX4Q gJW64u3iI7O7ZRWYbwy6MvKwQU5ooFfIsk9qOhELy379JLWof1RZHNP+X9JGps8kQT+5 jA0hQHyJe6KO0eXpHQgV2Xu8rX5mOUCnsmQAu4oPRUJ2gxGHdtahBcoHinTcDeajcE+9 M4nOhJ7FobcrRNmgD7sP0G2lAr9wzKtGajG/iIvfAJCPFxi9k5wMp5PXBwUOT8TLi3PR AjV6+kljJnEtKVtWHYMNX77zzJ3MvWBXVwjiiyR8/iaej2YOrvuO6gHYSY5NPuz942ha dweQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent :content-language:to:from:subject; bh=joe/VHjM3vFzOdXNr0FRiV3E7mTaokFEsnNbfeMiCHQ=; b=g8LoNWWTVCvE7w1VhaCb1ipM9BAljdMW5+lzSL3I3yBgjRjy1RxY034zM5l3mFluZC EJRRRacPEi1pdK0vASFXp/DKCeFUn0d4EgaOxLBAgjvob7iQXQnjzuzEwTGyDaEIsEk8 zT9lgou5XcY1uDSAnmq4C2AKMzkVJjBPzljOUBnv33/OLpz08XocZiR1Ti1QYp8wbDxT 75xmDxfi/uv1sabuBxx9AkcLB16iHSw4cS4JBbKkq6CUhU6TC2BpG5x7glUDn0PmlrWG EBcnssq3THNZXikyyHT/PVA+hD2NRtoOxVAkiVFjL1IH1js1j2Ak/uBG3qGYVdgPt1Fc 1wdg== X-Gm-Message-State: AOAM530f8Kg+hvqyiTPoM6jUo1w83bteH8g1wLxgmMKkyIOJE5CgdFA8 rJicKUBd6ttHsfK/pX43ZIpdIVVVdLuJXacB X-Received: by 2002:a17:902:e790:b0:149:7a3f:826a with SMTP id cp16-20020a170902e79000b001497a3f826amr45194146plb.76.1641393768373; Wed, 05 Jan 2022 06:42:48 -0800 (PST) Received: from [192.168.2.144] (113x41x203x65.ap113.ftth.ucom.ne.jp. [113.41.203.65]) by smtp.gmail.com with ESMTPSA id ot6sm3356033pjb.32.2022.01.05.06.42.46 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 05 Jan 2022 06:42:47 -0800 (PST) Message-ID: Date: Wed, 5 Jan 2022 23:42:45 +0900 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.4.1 Content-Language: en-US To: FFmpeg development discussions and patches From: Lucien Murray-Pitts Content-Disposition: attachment; filename="0001-Adds-DVD-protocol.v3.patch" X-Content-Filtered-By: Mailman/MimeDel 2.1.29 Subject: [FFmpeg-devel] [PATCH v3] Adds DVD protocol X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: cOMTx/UiKlQp Adds DVD protocol Copies the existing Bluray protocol format to add DVD protocol support using libdvdnav. Since title selection is mandatory ffprobe cant provide information for the complete disk but a single title only. Chapter information for probe will also be missing. To see a complete disk catalog of titles/chapters the tools/dvd2concat perl script should be used. Signed-off-by: Lucien Murray-Pitts --- configure | 4 + libavformat/Makefile | 1 + libavformat/dvd.c | 264 ++++++++++++++++++++++++++++++++++++++++ libavformat/protocols.c | 1 + 4 files changed, 270 insertions(+) create mode 100644 libavformat/dvd.c diff --git a/configure b/configure index 8392c26015..7f8b0046d2 100755 --- a/configure +++ b/configure @@ -230,6 +230,7 @@ External library support: --enable-libdavs2 enable AVS2 decoding via libdavs2 [no] --enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 and libraw1394 [no] + --enable-libdvdnav enable DVD reading using libdvdnav [no] --enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] --enable-libflite enable flite (voice synthesis) support via libflite [no] --enable-libfontconfig enable libfontconfig, useful for drawtext filter [no] @@ -1822,6 +1823,7 @@ EXTERNAL_LIBRARY_LIST=" libdav1d libdc1394 libdrm + libdvdnav libflite libfontconfig libfreetype @@ -3539,6 +3541,7 @@ xv_outdev_deps="xlib_xv xlib_x11 xlib_xext" # protocols async_protocol_deps="threads" bluray_protocol_deps="libbluray" +dvd_protocol_deps="libdvdnav" ffrtmpcrypt_protocol_conflict="librtmp_protocol" ffrtmpcrypt_protocol_deps_any="gcrypt gmp openssl mbedtls" ffrtmpcrypt_protocol_select="tcp_protocol" @@ -6526,6 +6529,7 @@ enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion +enabled libdvdnav && require_pkg_config libdvdnav dvdnav dvdnav/dvdnav.h dvdnav_open enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac && warn "using libfdk without pkg-config"; } } diff --git a/libavformat/Makefile b/libavformat/Makefile index c479ea998e..5fbba89e36 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -627,6 +627,7 @@ OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o OBJS-$(CONFIG_CONCATF_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o +OBJS-$(CONFIG_DVD_PROTOCOL) += dvd.o OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o diff --git a/libavformat/dvd.c b/libavformat/dvd.c new file mode 100644 index 0000000000..b3bc1b95e4 --- /dev/null +++ b/libavformat/dvd.c @@ -0,0 +1,264 @@ +/* + * DVD (libdvdnav) protocol based on BluRay (libbluray) protocol by Petri Hintukainen. + * + * Copyright (c) 2022 Lucien Murray-Pitts gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* + * REFERENCES: https://code.videolan.org/videolan/libdvdnav/-/blob/master/src/dvdnav/dvdnav.h + * https://code.videolan.org/videolan/libdvdnav/-/blob/master/examples/menus.c + * + * EXAMPLE USE: + * Choose Title 4, map 1/2/3 (video/audio/subtitles), copy the subtitles as is into mkv + * ./ffmpeg -playlist 4 -i dvd:"/mnt/MURDER_SHE_WROTE_TS.S10D1" -map 0:1 -map 0:2 -map 0:3 -vb 20M -codec:s copy remuxed-dvd.mkv + * + * Probe for info + * ./ffprobe -loglevel trace -fdebug 8 -playlist 19 -i dvd:"/mnt/MURDER_SHE_WROTE_TS.S10D1" -threads 0 -v warning -print_format json -show_streams -show_chapters -show_format + */ +#include + +#include "libavutil/avstring.h" +#include "libavformat/avformat.h" +#include "libavformat/url.h" +#include "libavutil/opt.h" + +#define DVD_PROTO_PREFIX "dvd:" + +typedef struct { + const AVClass *class; + + dvdnav_t *dvdnav; + + int playlist; + int angle; + int chapter; + /*int region;*/ +} DVDContext; + +#define OFFSET(x) offsetof(DVDContext, x) +static const AVOption options[] = { +{"playlist", "DVD title to play", OFFSET(playlist), AV_OPT_TYPE_INT, { .i64=-1 }, -1, 99999, AV_OPT_FLAG_DECODING_PARAM }, +{"angle", "DVD Video stream angle", OFFSET(angle), AV_OPT_TYPE_INT, { .i64=0 }, 0, 0xfe, AV_OPT_FLAG_DECODING_PARAM }, +{"chapter", "DVD Chapter to play", OFFSET(chapter), AV_OPT_TYPE_INT, { .i64=1 }, 1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM }, +/*{"region", "dvd player region code (1 = region A, 2 = region B, 4 = region C)", OFFSET(region), AV_OPT_TYPE_INT, { .i64=0 }, 0, 3, AV_OPT_FLAG_DECODING_PARAM },*/ +{NULL} +}; + +static const AVClass dvd_context_class = { + .class_name = "dvd", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + + +static int check_disc_info(URLContext *h) +{ + DVDContext *disk = h->priv_data; + + int32_t region_mask; + + // Gets the DVD DISK's region; confirms if disk is at least readable + if ( !dvdnav_get_region_mask( disk->dvdnav, ®ion_mask) ) { + av_log(h, AV_LOG_ERROR, "dvdnav_get_region_mask() failed\n"); + return -1; + } + + av_log(h, AV_LOG_INFO, "dvdnav_get_region_mask() got %i\n", region_mask); + + return 0; +} + +static int dvd_close(URLContext *h) +{ + DVDContext *disk = h->priv_data; + if (disk->dvdnav) { + dvdnav_close( disk->dvdnav ); + } + + return 0; +} + +static int dvd_open(URLContext *h, const char *path, int flags) +{ + DVDContext *disk = h->priv_data; + int num_title_idx; + const char *diskname = path; + + av_strstart(path, DVD_PROTO_PREFIX, &diskname); + + if ( dvdnav_open(&disk->dvdnav, diskname) != DVDNAV_STATUS_OK ) { + av_log(h, AV_LOG_ERROR, "dvdnav_open() failed, problem opening DVD folder/drive\n"); + return AVERROR(EIO); + } + + /* check if disc can be played */ + if (check_disc_info(h) < 0) { + return AVERROR(EIO); + } + + /* setup player registers */ + /* region code has no effect without menus + if (disk->region > 0 && disk->region < 5) { + av_log(h, AV_LOG_INFO, "setting region code to %d (%c)\n", disk->region, 'A' + (disk->region - 1)); + } + */ + + /* load title list */ + dvdnav_get_number_of_titles(disk->dvdnav, &num_title_idx); + if (num_title_idx < 1) { + av_log(h, AV_LOG_ERROR, "no usable dvd titles found on disk\n"); + return AVERROR(EIO); + } + + av_log(h, AV_LOG_INFO, "%d usable dvd titles\n", num_title_idx); + + /* if playlist was not given, select longest playlist */ + if (disk->playlist < 0) { + uint64_t duration = 0; + int i; + for (i = 1; i <= num_title_idx; i++) { + uint64_t *times ; + uint64_t _duration; + + uint32_t chcount = dvdnav_describe_title_chapters( disk->dvdnav, i, ×, &_duration ); + if( chcount==0 ) continue; + + // Title complete length + av_log(h, AV_LOG_INFO, "title #%05d (%d:%02d:%02d)\n", + i, + ((int)(_duration / 90000) / 3600), + ((int)(_duration / 90000) % 3600) / 60, + ((int)(_duration / 90000) % 60)); + + // Display Chapter times + for( int tidx=0 ; tidx duration) { + disk->playlist = i; + duration = _duration; + } + + free(times); + } + } + av_log(h, AV_LOG_INFO, "selected title# %05d\n", disk->playlist); + + /* select playlist */ + if ( dvdnav_title_play(disk->dvdnav, disk->playlist) <= 0) { + av_log(h, AV_LOG_ERROR, "dvdnav_title_play(%05d) failed, title doesnt exist or is corrupted.\n", disk->playlist); + return AVERROR(EIO); + } + + + /* select angle; note angles may appear during video stream and not at the start */ + if (disk->angle >= 0) { + if( dvdnav_angle_change(disk->dvdnav, disk->angle) ) { + av_log(h, AV_LOG_ERROR, "selected angle doesnt exist\n"); + } + } + + + /* select chapter */ + if (disk->chapter > 1) { + uint64_t *times ; + uint64_t _duration; + + uint32_t chcount = dvdnav_describe_title_chapters( disk->dvdnav, disk->playlist, ×, &_duration ); + if(chcount == 0) { + av_log(h, AV_LOG_ERROR, "Title %05d description failed, title doesnt exist or is corrupted.\n", disk->playlist); + return AVERROR(EIO); + } + + if(disk->chapter > chcount) { + av_log(h, AV_LOG_ERROR, "Chapter %05d is out of range of 1..%05d for title %05d.\n", disk->chapter, chcount, disk->playlist); + return AVERROR(EIO); + } + + av_log(h, AV_LOG_INFO, " Seeking to: %05ld pts, start of chapter %05d\n", times[disk->chapter - 2], disk->chapter ); + dvdnav_time_search(disk->dvdnav, times[disk->chapter - 2] ); + + free(times); + } + + return 0; +} + +static int dvd_read(URLContext *h, unsigned char *buf, int size) +{ + DVDContext *disk = h->priv_data; + int32_t event; + int len; + + if (!disk || !disk->dvdnav) { + return AVERROR(EFAULT); + } + + dvdnav_get_next_block(disk->dvdnav, (uint8_t *)buf, &event, &len); + + return len == 0 ? AVERROR_EOF : len; +} + +static int64_t dvd_seek(URLContext *h, int64_t pos, int whence) +{ + DVDContext *disk = h->priv_data; + uint32_t curpos; + uint32_t len ; + + if (!disk || !disk->dvdnav) { + return AVERROR(EFAULT); + } + + switch (whence) { + case SEEK_SET: + case SEEK_CUR: + case SEEK_END: + dvdnav_get_position_in_title(disk->dvdnav, &curpos, &len); + dvdnav_sector_search(disk->dvdnav, pos, whence); + return curpos; + + case AVSEEK_SIZE: + dvdnav_get_position_in_title(disk->dvdnav, &curpos, &len); + return len ; + } + + av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence); + return AVERROR(EINVAL); +} + + +const URLProtocol ff_dvd_protocol = { + .name = "dvd", + .url_close = dvd_close, + .url_open = dvd_open, + .url_read = dvd_read, + .url_seek = dvd_seek, + .priv_data_size = sizeof(DVDContext), + .priv_data_class = &dvd_context_class, +}; diff --git a/libavformat/protocols.c b/libavformat/protocols.c index 948fae411f..4cbcedb5c8 100644 --- a/libavformat/protocols.c +++ b/libavformat/protocols.c @@ -30,6 +30,7 @@ extern const URLProtocol ff_concat_protocol; extern const URLProtocol ff_concatf_protocol; extern const URLProtocol ff_crypto_protocol; extern const URLProtocol ff_data_protocol; +extern const URLProtocol ff_dvd_protocol; extern const URLProtocol ff_ffrtmpcrypt_protocol; extern const URLProtocol ff_ffrtmphttp_protocol; extern const URLProtocol ff_file_protocol;