Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * BluRay (libbluray) protocol
3
 *
4
 * Copyright (c) 2012 Petri Hintukainen  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 
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
};