bluray protocol
authorPetri Hintukainen <phintuka@users.sourceforge.net>
Sat, 3 Mar 2012 03:25:48 +0000 (04:25 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 3 Mar 2012 03:30:49 +0000 (04:30 +0100)
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Changelog
MAINTAINERS
configure
doc/protocols.texi
libavformat/Makefile
libavformat/allformats.c
libavformat/bluray.c [new file with mode: 0644]

index 8741e24..9679f83 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -10,6 +10,7 @@ version next:
 - Sun Rasterfile Encoder
 - ID3v2 attached pictures reading and writing
 - WMA Lossless decoder
+- bluray protocol
 
 
 version 0.10:
index 7a04209..845f2f5 100644 (file)
@@ -370,6 +370,7 @@ Muxers/Demuxers:
   wv.c                                  Kostya Shishkov
 
 Protocols:
+  bluray.c                              Petri Hintukainen
   http.c                                Ronald S. Bultje
   mms*.c                                Ronald S. Bultje
   udp.c                                 Luca Abeni
index 6324690..b92609a 100755 (executable)
--- a/configure
+++ b/configure
@@ -171,6 +171,7 @@ External library support:
   --enable-gnutls          enable gnutls [no]
   --enable-libaacplus      enable AAC+ encoding via libaacplus [no]
   --enable-libass          enable libass subtitles rendering [no]
+  --enable-libbluray       enable BluRay reading using libbluray [no]
   --enable-libcelt         enable CELT decoding via libcelt [no]
   --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
@@ -1029,6 +1030,7 @@ CONFIG_LIST="
     huffman
     libaacplus
     libass
+    libbluray
     libcdio
     libcelt
     libdc1394
@@ -1633,6 +1635,7 @@ x11_grab_device_indev_deps="x11grab XShmCreateImage"
 x11_grab_device_indev_extralibs="-lX11 -lXext -lXfixes"
 
 # protocols
+bluray_protocol_deps="libbluray"
 gopher_protocol_deps="network"
 httpproxy_protocol_deps="network"
 httpproxy_protocol_select="tcp_protocol"
@@ -3140,6 +3143,7 @@ enabled frei0r     && { check_header frei0r.h || die "ERROR: frei0r.h header not
 enabled gnutls     && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
 enabled libaacplus && require  "libaacplus >= 2.0.0" aacplus.h aacplusEncOpen -laacplus
 enabled libass     && require_pkg_config libass ass/ass.h ass_library_init
+enabled libbluray  && require libbluray libbluray/bluray.h bd_open -lbluray
 enabled libcelt    && require libcelt celt/celt.h celt_decode -lcelt0 &&
                       { check_lib celt/celt.h celt_decoder_create_custom -lcelt0 ||
                         die "ERROR: libcelt version must be >= 0.11.0."; }
index 13aae78..782e2b0 100644 (file)
@@ -19,6 +19,36 @@ supported protocols.
 
 A description of the currently available protocols follows.
 
+@section bluray
+
+Read BluRay playlist.
+
+The accepted options are:
+@table @option
+
+@item angle
+BluRay angle
+
+@item chapter
+Start chapter (1...N)
+
+@item playlist
+Playlist to read (BDMV/PLAYLIST/?????.mpls)
+
+@end table
+
+Examples:
+
+Read longest playlist from BluRay mounted to /mnt/bluray:
+@example
+bluray:/mnt/bluray
+@end example
+
+Read angle 2 of playlist 4 from BluRay mounted to /mnt/bluray, start from chapter 2:
+@example
+-playlist 4 -angle 2 -chapter 2 bluray:/mnt/bluray
+@end example
+
 @section concat
 
 Physical concatenation protocol.
index 61bb112..5bf2fda 100644 (file)
@@ -353,6 +353,7 @@ OBJS-$(CONFIG_LIBRTMP)                   += librtmp.o
 OBJS+= avio.o aviobuf.o
 
 OBJS-$(CONFIG_APPLEHTTP_PROTOCOL)        += hlsproto.o
+OBJS-$(CONFIG_BLURAY_PROTOCOL)           += bluray.o
 OBJS-$(CONFIG_CACHE_PROTOCOL)            += cache.o
 OBJS-$(CONFIG_CONCAT_PROTOCOL)           += concat.o
 OBJS-$(CONFIG_CRYPTO_PROTOCOL)           += crypto.o
index 7648f7f..614b341 100644 (file)
@@ -260,6 +260,7 @@ void av_register_all(void)
 #if FF_API_APPLEHTTP_PROTO
     REGISTER_PROTOCOL (APPLEHTTP, applehttp);
 #endif
+    REGISTER_PROTOCOL (BLURAY, bluray);
     REGISTER_PROTOCOL (CACHE, cache);
     REGISTER_PROTOCOL (CONCAT, concat);
     REGISTER_PROTOCOL (CRYPTO, crypto);
diff --git a/libavformat/bluray.c b/libavformat/bluray.c
new file mode 100644 (file)
index 0000000..2f918b1
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * BluRay (libbluray) protocol
+ *
+ * Copyright (c) 2012 Petri Hintukainen <phintuka <at> users.sourceforge.net>
+ *
+ * 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
+ */
+
+#include <libbluray/bluray.h>
+
+#include "libavutil/avstring.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+#include "libavutil/opt.h"
+
+#define BLURAY_PROTO_PREFIX     "bluray:"
+#define MIN_PLAYLIST_LENGTH     180     /* 3 min */
+
+typedef struct {
+    const AVClass *class;
+
+    BLURAY *bd;
+
+    int playlist;
+    int angle;
+    int chapter;
+    /*int region;*/
+} BlurayContext;
+
+#define OFFSET(x) offsetof(BlurayContext, x)
+static const AVOption options[] = {
+{"playlist", "", OFFSET(playlist), AV_OPT_TYPE_INT, { .dbl=-1 }, -1,  99999, AV_OPT_FLAG_DECODING_PARAM },
+{"angle",    "", OFFSET(angle),    AV_OPT_TYPE_INT, { .dbl=0 },   0,   0xfe, AV_OPT_FLAG_DECODING_PARAM },
+{"chapter",  "", OFFSET(chapter),  AV_OPT_TYPE_INT, { .dbl=1 },   1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM },
+/*{"region",   "bluray player region code (1 = region A, 2 = region B, 4 = region C)", OFFSET(region), AV_OPT_TYPE_INT, { .dbl=0 }, 0, 3, AV_OPT_FLAG_DECODING_PARAM },*/
+{NULL}
+};
+
+static const AVClass bluray_context_class = {
+    .class_name     = "bluray",
+    .item_name      = av_default_item_name,
+    .option         = options,
+    .version        = LIBAVUTIL_VERSION_INT,
+};
+
+
+static int check_disc_info(URLContext *h)
+{
+    BlurayContext *bd = h->priv_data;
+    const BLURAY_DISC_INFO *disc_info;
+
+    disc_info = bd_get_disc_info(bd->bd);
+    if (!disc_info) {
+        av_log(h, AV_LOG_ERROR, "bd_get_disc_info() failed\n");
+        return -1;
+    }
+
+    if (!disc_info->bluray_detected) {
+        av_log(h, AV_LOG_ERROR, "BluRay disc not detected\n");
+        return -1;
+    }
+
+    /* AACS */
+    if (disc_info->aacs_detected && !disc_info->aacs_handled) {
+        if (!disc_info->libaacs_detected) {
+            av_log(h, AV_LOG_ERROR,
+                   "Media stream encrypted with AACS, install and configure libaacs\n");
+        } else {
+            av_log(h, AV_LOG_ERROR, "Your libaacs can't decrypt this media\n");
+        }
+        return -1;
+    }
+
+    /* BD+ */
+    if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
+        /*
+        if (!disc_info->libbdplus_detected) {
+            av_log(h, AV_LOG_ERROR,
+                   "Media stream encrypted with BD+, install and configure libbdplus");
+        } else {
+        */
+            av_log(h, AV_LOG_ERROR, "Unable to decrypt BD+ encrypted media");
+        /*}*/
+        return -1;
+    }
+
+    return 0;
+}
+
+static int bluray_close(URLContext *h)
+{
+    BlurayContext *bd = h->priv_data;
+    if (bd->bd) {
+        bd_close(bd->bd);
+    }
+
+    return 0;
+}
+
+static int bluray_open(URLContext *h, const char *path, int flags)
+{
+    BlurayContext *bd = h->priv_data;
+    int num_title_idx;
+    const char *diskname = path;
+
+    av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
+
+    bd->bd = bd_open(diskname, NULL);
+    if (!bd->bd) {
+        av_log(h, AV_LOG_ERROR, "bd_open() failed\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 (bd->region > 0 && bd->region < 5) {
+        av_log(h, AV_LOG_INFO, "setting region code to %d (%c)\n", bd->region, 'A' + (bd->region - 1));
+        bd_set_player_setting(bd->bd, BLURAY_PLAYER_SETTING_REGION_CODE, bd->region);
+    }
+    */
+
+    /* load title list */
+    num_title_idx = bd_get_titles(bd->bd, TITLES_RELEVANT, MIN_PLAYLIST_LENGTH);
+    av_log(h, AV_LOG_INFO, "%d usable playlists:\n", num_title_idx);
+    if (num_title_idx < 1) {
+        return AVERROR(EIO);
+    }
+
+    /* if playlist was not given, select longest playlist */
+    if (bd->playlist < 0) {
+        uint64_t duration = 0;
+        int i;
+        for (i = 0; i < num_title_idx; i++) {
+            BLURAY_TITLE_INFO *info = bd_get_title_info(bd->bd, i, 0);
+
+            av_log(h, AV_LOG_INFO, "playlist %05d.mpls (%d:%02d:%02d)\n",
+                   info->playlist,
+                   ((int)(info->duration / 90000) / 3600),
+                   ((int)(info->duration / 90000) % 3600) / 60,
+                   ((int)(info->duration / 90000) % 60));
+
+            if (info->duration > duration) {
+                bd->playlist = info->playlist;
+                duration = info->duration;
+            }
+
+            bd_free_title_info(info);
+        }
+        av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
+    }
+
+    /* select playlist */
+    if (bd_select_playlist(bd->bd, bd->playlist) <= 0) {
+        av_log(h, AV_LOG_ERROR, "bd_select_playlist(%05d.mpls) failed\n", bd->playlist);
+        return AVERROR(EIO);
+    }
+
+    /* select angle */
+    if (bd->angle >= 0) {
+        bd_select_angle(bd->bd, bd->angle);
+    }
+
+    /* select chapter */
+    if (bd->chapter > 1) {
+        bd_seek_chapter(bd->bd, bd->chapter - 1);
+    }
+
+    return 0;
+}
+
+static int bluray_read(URLContext *h, unsigned char *buf, int size)
+{
+    BlurayContext *bd = h->priv_data;
+    int len;
+
+    if (!bd || !bd->bd) {
+        return AVERROR(EFAULT);
+    }
+
+    len = bd_read(bd->bd, buf, size);
+
+    return len;
+}
+
+static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
+{
+    BlurayContext *bd = h->priv_data;
+
+    if (!bd || !bd->bd) {
+        return AVERROR(EFAULT);
+    }
+
+    switch (whence) {
+    case SEEK_SET:
+    case SEEK_CUR:
+    case SEEK_END:
+        return bd_seek(bd->bd, pos);
+
+    case AVSEEK_SIZE:
+        return bd_get_title_size(bd->bd);
+    }
+
+    av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence);
+    return AVERROR(EINVAL);
+}
+
+
+URLProtocol ff_bluray_protocol = {
+    .name            = "bluray",
+    .url_close       = bluray_close,
+    .url_open        = bluray_open,
+    .url_read        = bluray_read,
+    .url_seek        = bluray_seek,
+    .priv_data_size  = sizeof(BlurayContext),
+    .priv_data_class = &bluray_context_class,
+};