00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <libbluray/bluray.h>
00024
00025 #include "libavutil/avstring.h"
00026 #include "libavformat/avformat.h"
00027 #include "libavformat/url.h"
00028 #include "libavutil/opt.h"
00029
00030 #define BLURAY_PROTO_PREFIX "bluray:"
00031 #define MIN_PLAYLIST_LENGTH 180
00032
00033 typedef struct {
00034 const AVClass *class;
00035
00036 BLURAY *bd;
00037
00038 int playlist;
00039 int angle;
00040 int chapter;
00041
00042 } BlurayContext;
00043
00044 #define OFFSET(x) offsetof(BlurayContext, x)
00045 static const AVOption options[] = {
00046 {"playlist", "", OFFSET(playlist), AV_OPT_TYPE_INT, { .i64=-1 }, -1, 99999, AV_OPT_FLAG_DECODING_PARAM },
00047 {"angle", "", OFFSET(angle), AV_OPT_TYPE_INT, { .i64=0 }, 0, 0xfe, AV_OPT_FLAG_DECODING_PARAM },
00048 {"chapter", "", OFFSET(chapter), AV_OPT_TYPE_INT, { .i64=1 }, 1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM },
00049
00050 {NULL}
00051 };
00052
00053 static const AVClass bluray_context_class = {
00054 .class_name = "bluray",
00055 .item_name = av_default_item_name,
00056 .option = options,
00057 .version = LIBAVUTIL_VERSION_INT,
00058 };
00059
00060
00061 static int check_disc_info(URLContext *h)
00062 {
00063 BlurayContext *bd = h->priv_data;
00064 const BLURAY_DISC_INFO *disc_info;
00065
00066 disc_info = bd_get_disc_info(bd->bd);
00067 if (!disc_info) {
00068 av_log(h, AV_LOG_ERROR, "bd_get_disc_info() failed\n");
00069 return -1;
00070 }
00071
00072 if (!disc_info->bluray_detected) {
00073 av_log(h, AV_LOG_ERROR, "BluRay disc not detected\n");
00074 return -1;
00075 }
00076
00077
00078 if (disc_info->aacs_detected && !disc_info->aacs_handled) {
00079 if (!disc_info->libaacs_detected) {
00080 av_log(h, AV_LOG_ERROR,
00081 "Media stream encrypted with AACS, install and configure libaacs\n");
00082 } else {
00083 av_log(h, AV_LOG_ERROR, "Your libaacs can't decrypt this media\n");
00084 }
00085 return -1;
00086 }
00087
00088
00089 if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
00090
00091
00092
00093
00094
00095
00096 av_log(h, AV_LOG_ERROR, "Unable to decrypt BD+ encrypted media\n");
00097
00098 return -1;
00099 }
00100
00101 return 0;
00102 }
00103
00104 static int bluray_close(URLContext *h)
00105 {
00106 BlurayContext *bd = h->priv_data;
00107 if (bd->bd) {
00108 bd_close(bd->bd);
00109 }
00110
00111 return 0;
00112 }
00113
00114 static int bluray_open(URLContext *h, const char *path, int flags)
00115 {
00116 BlurayContext *bd = h->priv_data;
00117 int num_title_idx;
00118 const char *diskname = path;
00119
00120 av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
00121
00122 bd->bd = bd_open(diskname, NULL);
00123 if (!bd->bd) {
00124 av_log(h, AV_LOG_ERROR, "bd_open() failed\n");
00125 return AVERROR(EIO);
00126 }
00127
00128
00129 if (check_disc_info(h) < 0) {
00130 return AVERROR(EIO);
00131 }
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 num_title_idx = bd_get_titles(bd->bd, TITLES_RELEVANT, MIN_PLAYLIST_LENGTH);
00143 av_log(h, AV_LOG_INFO, "%d usable playlists:\n", num_title_idx);
00144 if (num_title_idx < 1) {
00145 return AVERROR(EIO);
00146 }
00147
00148
00149 if (bd->playlist < 0) {
00150 uint64_t duration = 0;
00151 int i;
00152 for (i = 0; i < num_title_idx; i++) {
00153 BLURAY_TITLE_INFO *info = bd_get_title_info(bd->bd, i, 0);
00154
00155 av_log(h, AV_LOG_INFO, "playlist %05d.mpls (%d:%02d:%02d)\n",
00156 info->playlist,
00157 ((int)(info->duration / 90000) / 3600),
00158 ((int)(info->duration / 90000) % 3600) / 60,
00159 ((int)(info->duration / 90000) % 60));
00160
00161 if (info->duration > duration) {
00162 bd->playlist = info->playlist;
00163 duration = info->duration;
00164 }
00165
00166 bd_free_title_info(info);
00167 }
00168 av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
00169 }
00170
00171
00172 if (bd_select_playlist(bd->bd, bd->playlist) <= 0) {
00173 av_log(h, AV_LOG_ERROR, "bd_select_playlist(%05d.mpls) failed\n", bd->playlist);
00174 return AVERROR(EIO);
00175 }
00176
00177
00178 if (bd->angle >= 0) {
00179 bd_select_angle(bd->bd, bd->angle);
00180 }
00181
00182
00183 if (bd->chapter > 1) {
00184 bd_seek_chapter(bd->bd, bd->chapter - 1);
00185 }
00186
00187 return 0;
00188 }
00189
00190 static int bluray_read(URLContext *h, unsigned char *buf, int size)
00191 {
00192 BlurayContext *bd = h->priv_data;
00193 int len;
00194
00195 if (!bd || !bd->bd) {
00196 return AVERROR(EFAULT);
00197 }
00198
00199 len = bd_read(bd->bd, buf, size);
00200
00201 return len;
00202 }
00203
00204 static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
00205 {
00206 BlurayContext *bd = h->priv_data;
00207
00208 if (!bd || !bd->bd) {
00209 return AVERROR(EFAULT);
00210 }
00211
00212 switch (whence) {
00213 case SEEK_SET:
00214 case SEEK_CUR:
00215 case SEEK_END:
00216 return bd_seek(bd->bd, pos);
00217
00218 case AVSEEK_SIZE:
00219 return bd_get_title_size(bd->bd);
00220 }
00221
00222 av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence);
00223 return AVERROR(EINVAL);
00224 }
00225
00226
00227 URLProtocol ff_bluray_protocol = {
00228 .name = "bluray",
00229 .url_close = bluray_close,
00230 .url_open = bluray_open,
00231 .url_read = bluray_read,
00232 .url_seek = bluray_seek,
00233 .priv_data_size = sizeof(BlurayContext),
00234 .priv_data_class = &bluray_context_class,
00235 };