Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * BluRay (libbluray) protocol
  3.  *
  4.  * Copyright (c) 2012 Petri Hintukainen <phintuka <at> users.sourceforge.net>
  5.  *
  6.  * This file is part of FFmpeg.
  7.  *
  8.  * FFmpeg is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Lesser General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2.1 of the License, or (at your option) any later version.
  12.  *
  13.  * FFmpeg is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Lesser General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with FFmpeg; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21.  */
  22.  
  23. #include <libbluray/bluray.h>
  24.  
  25. #include "libavutil/avstring.h"
  26. #include "libavformat/avformat.h"
  27. #include "libavformat/url.h"
  28. #include "libavutil/opt.h"
  29.  
  30. #define BLURAY_PROTO_PREFIX     "bluray:"
  31. #define MIN_PLAYLIST_LENGTH     180     /* 3 min */
  32.  
  33. typedef struct {
  34.     const AVClass *class;
  35.  
  36.     BLURAY *bd;
  37.  
  38.     int playlist;
  39.     int angle;
  40.     int chapter;
  41.     /*int region;*/
  42. } BlurayContext;
  43.  
  44. #define OFFSET(x) offsetof(BlurayContext, x)
  45. static const AVOption options[] = {
  46. {"playlist", "", OFFSET(playlist), AV_OPT_TYPE_INT, { .i64=-1 }, -1,  99999, AV_OPT_FLAG_DECODING_PARAM },
  47. {"angle",    "", OFFSET(angle),    AV_OPT_TYPE_INT, { .i64=0 },   0,   0xfe, AV_OPT_FLAG_DECODING_PARAM },
  48. {"chapter",  "", OFFSET(chapter),  AV_OPT_TYPE_INT, { .i64=1 },   1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM },
  49. /*{"region",   "bluray 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 },*/
  50. {NULL}
  51. };
  52.  
  53. static const AVClass bluray_context_class = {
  54.     .class_name     = "bluray",
  55.     .item_name      = av_default_item_name,
  56.     .option         = options,
  57.     .version        = LIBAVUTIL_VERSION_INT,
  58. };
  59.  
  60.  
  61. static int check_disc_info(URLContext *h)
  62. {
  63.     BlurayContext *bd = h->priv_data;
  64.     const BLURAY_DISC_INFO *disc_info;
  65.  
  66.     disc_info = bd_get_disc_info(bd->bd);
  67.     if (!disc_info) {
  68.         av_log(h, AV_LOG_ERROR, "bd_get_disc_info() failed\n");
  69.         return -1;
  70.     }
  71.  
  72.     if (!disc_info->bluray_detected) {
  73.         av_log(h, AV_LOG_ERROR, "BluRay disc not detected\n");
  74.         return -1;
  75.     }
  76.  
  77.     /* AACS */
  78.     if (disc_info->aacs_detected && !disc_info->aacs_handled) {
  79.         if (!disc_info->libaacs_detected) {
  80.             av_log(h, AV_LOG_ERROR,
  81.                    "Media stream encrypted with AACS, install and configure libaacs\n");
  82.         } else {
  83.             av_log(h, AV_LOG_ERROR, "Your libaacs can't decrypt this media\n");
  84.         }
  85.         return -1;
  86.     }
  87.  
  88.     /* BD+ */
  89.     if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
  90.         /*
  91.         if (!disc_info->libbdplus_detected) {
  92.             av_log(h, AV_LOG_ERROR,
  93.                    "Media stream encrypted with BD+, install and configure libbdplus");
  94.         } else {
  95.         */
  96.             av_log(h, AV_LOG_ERROR, "Unable to decrypt BD+ encrypted media\n");
  97.         /*}*/
  98.         return -1;
  99.     }
  100.  
  101.     return 0;
  102. }
  103.  
  104. static int bluray_close(URLContext *h)
  105. {
  106.     BlurayContext *bd = h->priv_data;
  107.     if (bd->bd) {
  108.         bd_close(bd->bd);
  109.     }
  110.  
  111.     return 0;
  112. }
  113.  
  114. static int bluray_open(URLContext *h, const char *path, int flags)
  115. {
  116.     BlurayContext *bd = h->priv_data;
  117.     int num_title_idx;
  118.     const char *diskname = path;
  119.  
  120.     av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
  121.  
  122.     bd->bd = bd_open(diskname, NULL);
  123.     if (!bd->bd) {
  124.         av_log(h, AV_LOG_ERROR, "bd_open() failed\n");
  125.         return AVERROR(EIO);
  126.     }
  127.  
  128.     /* check if disc can be played */
  129.     if (check_disc_info(h) < 0) {
  130.         return AVERROR(EIO);
  131.     }
  132.  
  133.     /* setup player registers */
  134.     /* region code has no effect without menus
  135.     if (bd->region > 0 && bd->region < 5) {
  136.         av_log(h, AV_LOG_INFO, "setting region code to %d (%c)\n", bd->region, 'A' + (bd->region - 1));
  137.         bd_set_player_setting(bd->bd, BLURAY_PLAYER_SETTING_REGION_CODE, bd->region);
  138.     }
  139.     */
  140.  
  141.     /* load title list */
  142.     num_title_idx = bd_get_titles(bd->bd, TITLES_RELEVANT, MIN_PLAYLIST_LENGTH);
  143.     av_log(h, AV_LOG_INFO, "%d usable playlists:\n", num_title_idx);
  144.     if (num_title_idx < 1) {
  145.         return AVERROR(EIO);
  146.     }
  147.  
  148.     /* if playlist was not given, select longest playlist */
  149.     if (bd->playlist < 0) {
  150.         uint64_t duration = 0;
  151.         int i;
  152.         for (i = 0; i < num_title_idx; i++) {
  153.             BLURAY_TITLE_INFO *info = bd_get_title_info(bd->bd, i, 0);
  154.  
  155.             av_log(h, AV_LOG_INFO, "playlist %05d.mpls (%d:%02d:%02d)\n",
  156.                    info->playlist,
  157.                    ((int)(info->duration / 90000) / 3600),
  158.                    ((int)(info->duration / 90000) % 3600) / 60,
  159.                    ((int)(info->duration / 90000) % 60));
  160.  
  161.             if (info->duration > duration) {
  162.                 bd->playlist = info->playlist;
  163.                 duration = info->duration;
  164.             }
  165.  
  166.             bd_free_title_info(info);
  167.         }
  168.         av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
  169.     }
  170.  
  171.     /* select playlist */
  172.     if (bd_select_playlist(bd->bd, bd->playlist) <= 0) {
  173.         av_log(h, AV_LOG_ERROR, "bd_select_playlist(%05d.mpls) failed\n", bd->playlist);
  174.         return AVERROR(EIO);
  175.     }
  176.  
  177.     /* select angle */
  178.     if (bd->angle >= 0) {
  179.         bd_select_angle(bd->bd, bd->angle);
  180.     }
  181.  
  182.     /* select chapter */
  183.     if (bd->chapter > 1) {
  184.         bd_seek_chapter(bd->bd, bd->chapter - 1);
  185.     }
  186.  
  187.     return 0;
  188. }
  189.  
  190. static int bluray_read(URLContext *h, unsigned char *buf, int size)
  191. {
  192.     BlurayContext *bd = h->priv_data;
  193.     int len;
  194.  
  195.     if (!bd || !bd->bd) {
  196.         return AVERROR(EFAULT);
  197.     }
  198.  
  199.     len = bd_read(bd->bd, buf, size);
  200.  
  201.     return len;
  202. }
  203.  
  204. static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
  205. {
  206.     BlurayContext *bd = h->priv_data;
  207.  
  208.     if (!bd || !bd->bd) {
  209.         return AVERROR(EFAULT);
  210.     }
  211.  
  212.     switch (whence) {
  213.     case SEEK_SET:
  214.     case SEEK_CUR:
  215.     case SEEK_END:
  216.         return bd_seek(bd->bd, pos);
  217.  
  218.     case AVSEEK_SIZE:
  219.         return bd_get_title_size(bd->bd);
  220.     }
  221.  
  222.     av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence);
  223.     return AVERROR(EINVAL);
  224. }
  225.  
  226.  
  227. URLProtocol ff_bluray_protocol = {
  228.     .name            = "bluray",
  229.     .url_close       = bluray_close,
  230.     .url_open        = bluray_open,
  231.     .url_read        = bluray_read,
  232.     .url_seek        = bluray_seek,
  233.     .priv_data_size  = sizeof(BlurayContext),
  234.     .priv_data_class = &bluray_context_class,
  235. };
  236.