Petri Hintukainen pushed to branch master at VideoLAN / libbluray


Commits:
4c785b60 by Masstock at 2026-01-18T23:42:43+01:00
Enforce UO restriction level

- - - - -


3 changed files:

- src/libbluray/bdnav/uo_mask_table.h
- src/libbluray/bluray.c
- src/libbluray/bluray.h


Changes:

=====================================
src/libbluray/bdnav/uo_mask_table.h
=====================================
@@ -20,10 +20,38 @@
 #if !defined(_BD_UO_MASK_TABLE_H_)
 #define _BD_UO_MASK_TABLE_H_
 
-enum {
-    UO_MASK_MENU_CALL_INDEX = 0,
-    UO_MASK_TITLE_SEARCH_INDEX = 1,
-};
+typedef enum {
+    UO_MASK_MENU_CALL_INDEX                           = 0,
+    UO_MASK_TITLE_SEARCH_INDEX                        = 1,
+    UO_MASK_CHAPTER_SEARCH_INDEX                      = 2,
+    UO_MASK_TIME_SEARCH_MASK_INDEX                    = 3,
+    UO_MASK_SKIP_TO_NEXT_POINT_MASK_INDEX             = 4,
+    UO_MASK_SKIP_BACK_TO_PREVIOUS_POINT_MASK_INDEX    = 5,
+    UO_MASK_STOP_MASK_INDEX                           = 7,
+    UO_MASK_PAUSE_ON_MASK_INDEX                       = 8,
+    UO_MASK_STILL_OFF_MASK_INDEX                      = 10,
+    UO_MASK_FORWARD_PLAY_MASK_INDEX                   = 11,
+    UO_MASK_BACKWARD_PLAY_MASK_INDEX                  = 12,
+    UO_MASK_RESUME_MASK_INDEX                         = 13,
+    UO_MASK_MOVE_UP_SELECTED_BUTTON_MASK_INDEX        = 14,
+    UO_MASK_MOVE_DOWN_SELECTED_BUTTON_MASK_INDEX      = 15,
+    UO_MASK_MOVE_LEFT_SELECTED_BUTTON_MASK_INDEX      = 16,
+    UO_MASK_MOVE_RIGHT_SELECTED_BUTTON_MASK_INDEX     = 17,
+    UO_MASK_SELECT_BUTTON_MASK_INDEX                  = 18,
+    UO_MASK_ACTIVATE_BUTTON_MASK_INDEX                = 19,
+    UO_MASK_SELECT_AND_ACTIVATE_MASK_INDEX            = 20,
+    UO_MASK_PRIMARY_AUDIO_CHANGE_MASK_INDEX           = 21,
+    UO_MASK_ANGLE_CHANGE_MASK_INDEX                   = 23,
+    UO_MASK_POPUP_ON_MASK_INDEX                       = 24,
+    UO_MASK_POPUP_OFF_MASK_INDEX                      = 25,
+    UO_MASK_PG_TEXTST_ENABLE_DISABLE_MASK_INDEX       = 26,
+    UO_MASK_PG_TEXTST_CHANGE_MASK_INDEX               = 27,
+    UO_MASK_SECONDARY_VIDEO_ENABLE_DISABLE_MASK_INDEX = 28,
+    UO_MASK_SECONDARY_VIDEO_CHANGE_MASK_INDEX         = 29,
+    UO_MASK_SECONDARY_AUDIO_ENABLE_DISABLE_MASK_INDEX = 30,
+    UO_MASK_SECONDARY_AUDIO_CHANGE_MASK_INDEX         = 31,
+    UO_MASK_PIP_PG_TEXTST_CHANGE_MASK_INDEX           = 33,
+} bd_uo_mask_index_e;
 
 typedef struct bd_uo_mask_table
 {


=====================================
src/libbluray/bluray.c
=====================================
@@ -1227,7 +1227,7 @@ void bd_set_bdj_uo_mask(BLURAY *bd, unsigned mask)
 
 uint64_t bd_get_uo_mask(BLURAY *bd)
 {
-    /* internal function. Used by BD-J. */
+    /* internal function. Used by BD-J (and UO masking checks). */
     union {
       uint64_t u64;
       BD_UO_MASK mask;
@@ -1240,6 +1240,11 @@ uint64_t bd_get_uo_mask(BLURAY *bd)
     return mask.u64;
 }
 
+static int _is_uo_masked(BLURAY *bd, bd_uo_mask_index_e mask_index)
+{
+    return (bd->title_type != title_undef) && !!(bd_get_uo_mask(bd) & (1ull << 
mask_index));
+}
+
 void bd_set_bdj_kit(BLURAY *bd, int mask)
 {
     _queue_event(bd, BD_EVENT_KEY_INTEREST_TABLE, mask);
@@ -1277,6 +1282,8 @@ void bd_select_rate(BLURAY *bd, float rate, int reason)
     }
 }
 
+static int64_t _seek_time(BLURAY *bd, uint64_t tick, uint8_t 
is_uo_mask_checked);
+
 int bd_bdj_seek(BLURAY *bd, int playitem, int playmark, int64_t time)
 {
     bd_mutex_lock(&bd->mutex);
@@ -1288,7 +1295,7 @@ int bd_bdj_seek(BLURAY *bd, int playitem, int playmark, 
int64_t time)
         bd_seek_mark(bd, playmark);
     }
     if (time >= 0) {
-        bd_seek_time(bd, time);
+        _seek_time(bd, time, 0);
     }
 
     bd_mutex_unlock(&bd->mutex);
@@ -1750,7 +1757,7 @@ static void _change_angle(BLURAY *bd)
     }
 }
 
-int64_t bd_seek_time(BLURAY *bd, uint64_t tick)
+static int64_t _seek_time(BLURAY *bd, uint64_t tick, uint8_t 
is_uo_mask_checked)
 {
     uint32_t clip_pkt, out_pkt;
     const NAV_CLIP *clip;
@@ -1760,9 +1767,18 @@ int64_t bd_seek_time(BLURAY *bd, uint64_t tick)
         return bd->s_pos;
     }
 
-    tick /= 2;
+    tick /= 2; // Convert to 45kHz clock ticks
 
-    bd_mutex_lock(&bd->mutex);
+    /* Check UO mask */
+    if (is_uo_mask_checked) {
+        const bd_uo_mask_index_e uo_mask_idx = UO_MASK_TIME_SEARCH_MASK_INDEX;
+
+        if (_is_uo_masked(bd, uo_mask_idx)) {
+            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_seek_time(%" PRIu64 ") UO %d 
restricted\n", tick, uo_mask_idx);
+            _bdj_event(bd, BDJ_EVENT_UO_MASKED, uo_mask_idx);
+            return -1;
+        }
+    }
 
     if (bd->title &&
         tick < bd->title->duration) {
@@ -1775,12 +1791,23 @@ int64_t bd_seek_time(BLURAY *bd, uint64_t tick)
         _seek_internal(bd, clip, out_pkt, clip_pkt);
 
     } else {
-        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_seek_time(%u) failed\n", (unsigned 
int)tick);
+        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_seek_time(%" PRIu64 ") failed\n", 
tick);
     }
 
+    return bd->s_pos;
+}
+
+int64_t bd_seek_time(BLURAY *bd, uint64_t tick)
+{
+    int64_t ret = 0;
+
+    bd_mutex_lock(&bd->mutex);
+
+    ret = _seek_time(bd, tick, BLURAY_PLAYER_SETTING_UO_RESTRICTION_SAFE <= 
bd->uo_restriction_level);
+
     bd_mutex_unlock(&bd->mutex);
 
-    return bd->s_pos;
+    return ret;
 }
 
 uint64_t bd_tell_time(BLURAY *bd)
@@ -1808,28 +1835,42 @@ uint64_t bd_tell_time(BLURAY *bd)
 
 int64_t bd_seek_chapter(BLURAY *bd, unsigned chapter)
 {
+    int is_uo_mask_checked;
     uint32_t clip_pkt, out_pkt;
     const NAV_CLIP *clip;
+    int64_t ret_pos;
 
     bd_mutex_lock(&bd->mutex);
+    is_uo_mask_checked = (BLURAY_PLAYER_SETTING_UO_RESTRICTION_SAFE < 
bd->uo_restriction_level);
 
-    if (bd->title &&
-        chapter < bd->title->chap_list.count) {
+    ret_pos = bd->s_pos; // Return current position by default
+    if (bd->title && chapter < bd->title->chap_list.count) {
+        /* Check chapter jump direction for UO restriction */
+        const bd_uo_mask_index_e uo_mask_idx = UO_MASK_CHAPTER_SEARCH_INDEX;
 
         _change_angle(bd);
 
-        // Find the closest access unit to the requested position
-        clip = nav_chapter_search(bd->title, chapter, &clip_pkt, &out_pkt);
+        if (is_uo_mask_checked && _is_uo_masked(bd, uo_mask_idx)) {
+            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_seek_chapter(%u) UO %d 
restricted\n", chapter, uo_mask_idx);
+            _bdj_event(bd, BDJ_EVENT_UO_MASKED, uo_mask_idx);
+            ret_pos = -1;
+        } else {
+            /* Seek chapter */
+            _change_angle(bd);
 
-        _seek_internal(bd, clip, out_pkt, clip_pkt);
+            // Find the closest access unit to the requested position
+            clip = nav_chapter_search(bd->title, chapter, &clip_pkt, &out_pkt);
 
+            _seek_internal(bd, clip, out_pkt, clip_pkt);
+            ret_pos = bd->s_pos; // Update
+        }
     } else {
         BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_seek_chapter(%u) failed\n", 
chapter);
     }
 
     bd_mutex_unlock(&bd->mutex);
 
-    return bd->s_pos;
+    return ret_pos;
 }
 
 int64_t bd_chapter_pos(BLURAY *bd, unsigned chapter)
@@ -2621,7 +2662,7 @@ uint32_t bd_get_current_title(BLURAY *bd)
     return bd->title_idx;
 }
 
-static int _bd_select_angle(BLURAY *bd, unsigned angle)
+static int _bd_select_angle(BLURAY *bd, unsigned angle, uint8_t 
is_uo_mask_checked)
 {
     unsigned orig_angle;
 
@@ -2630,6 +2671,17 @@ static int _bd_select_angle(BLURAY *bd, unsigned angle)
         return 0;
     }
 
+    /* Check UO mask */
+    if (is_uo_mask_checked) {
+        const bd_uo_mask_index_e uo_mask_idx = UO_MASK_ANGLE_CHANGE_MASK_INDEX;
+
+        if (_is_uo_masked(bd, uo_mask_idx)) {
+            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_select_angle(%u) UO %d 
restricted\n", angle, uo_mask_idx);
+            _bdj_event(bd, BDJ_EVENT_UO_MASKED, uo_mask_idx);
+            return 0;
+        }
+    }
+
     orig_angle = bd->title->angle;
 
     nav_set_angle(bd->title, angle);
@@ -2651,9 +2703,11 @@ static int _bd_select_angle(BLURAY *bd, unsigned angle)
 int bd_select_angle(BLURAY *bd, unsigned angle)
 {
     int result;
+
     bd_mutex_lock(&bd->mutex);
-    result = _bd_select_angle(bd, angle);
+    result = _bd_select_angle(bd, angle, 
BLURAY_PLAYER_SETTING_UO_RESTRICTION_COMPLIANT <= bd->uo_restriction_level);
     bd_mutex_unlock(&bd->mutex);
+
     return result;
 }
 
@@ -3061,18 +3115,85 @@ int bd_set_player_setting_str(BLURAY *bd, uint32_t idx, 
const char *s)
     }
 }
 
-void bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t stream_id, 
uint32_t enable_flag)
+static int _select_audio_stream(BLURAY *bd, uint32_t stream_id, int 
is_checked_uo_mask)
+{
+    /* Check Primary Audio Stream Number Change UO */
+    if (is_checked_uo_mask) {
+        const bd_uo_mask_index_e uo_mask_idx = 
UO_MASK_PRIMARY_AUDIO_CHANGE_MASK_INDEX;
+
+        if (_is_uo_masked(bd, uo_mask_idx)) {
+            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "_select_audio_stream(%" PRIu32 ") 
UO %d restricted\n",
+                stream_id, uo_mask_idx);
+            _bdj_event(bd, BDJ_EVENT_UO_MASKED, uo_mask_idx);
+            return 0;
+        }
+    }
+
+    bd_psr_write(bd->regs, PSR_PRIMARY_AUDIO_ID, stream_id & 0xff);
+    return 1;
+}
+
+static int _select_pg_textst_stream(BLURAY *bd, uint32_t stream_id, uint32_t 
enable_flag, int is_checked_uo_mask)
 {
+    uint32_t psr_initial_value = 0x0;
+    uint32_t psr_update_value = 0x0;
+    uint32_t psr_update_mask = 0x0;
+
+    /* Get initial PSR value to check for changes */
+    psr_initial_value = bd_psr_read(bd->regs, PSR_PG_STREAM);
+
+    /* Check PG textST Enable Disable UO */
+    if (!enable_flag != !(psr_initial_value & 0x80000000)) {
+        const bd_uo_mask_index_e uo_mask_idx = 
UO_MASK_PG_TEXTST_ENABLE_DISABLE_MASK_INDEX;
+
+        if (is_checked_uo_mask && _is_uo_masked(bd, uo_mask_idx)) {
+            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "_select_pg_textst_stream(%" 
PRIu32 ", %" PRIu32 ") UO %d restricted\n",
+                stream_id, enable_flag, uo_mask_idx);
+            _bdj_event(bd, BDJ_EVENT_UO_MASKED, uo_mask_idx);
+        } else {
+            // Enable/Disable PSR value
+            psr_update_value |= (!!enable_flag) << 31;
+            psr_update_mask  |= 0x80000000;
+        }
+    }
+
+    /* Check PG textST Stream Number Change UO */
+    if (stream_id != (psr_initial_value & 0xfff)) {
+        const bd_uo_mask_index_e uo_mask_idx = 
UO_MASK_PG_TEXTST_CHANGE_MASK_INDEX;
+
+        if (is_checked_uo_mask && _is_uo_masked(bd, uo_mask_idx)) {
+            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "_select_pg_textst_stream(%" 
PRIu32 ", %" PRIu32 ") UO %d restricted\n",
+                stream_id, enable_flag, uo_mask_idx);
+            _bdj_event(bd, BDJ_EVENT_UO_MASKED, uo_mask_idx);
+        } else {
+            psr_update_value |= stream_id & 0xfff;
+            psr_update_mask  |= 0xfff;
+        }
+    }
+
+    if (psr_update_mask) {
+        bd_psr_write_bits(bd->regs, PSR_PG_STREAM, psr_update_value, 
psr_update_mask);
+    }
+
+    return !!psr_update_mask;
+}
+
+int bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t stream_id, 
uint32_t enable_flag)
+{
+    int is_checked_uo_mask = 0;
+    int ret = -1;
+
     bd_mutex_lock(&bd->mutex);
 
+    /* Selecting stream should be a safe UO */
+    is_checked_uo_mask = (BLURAY_PLAYER_SETTING_UO_RESTRICTION_COMPLIANT <= 
bd->uo_restriction_level);
+
     switch (stream_type) {
         case BLURAY_AUDIO_STREAM:
-            bd_psr_write(bd->regs, PSR_PRIMARY_AUDIO_ID, stream_id & 0xff);
+            ret = _select_audio_stream(bd, stream_id, is_checked_uo_mask);
             break;
         case BLURAY_PG_TEXTST_STREAM:
-            bd_psr_write_bits(bd->regs, PSR_PG_STREAM,
-                              ((!!enable_flag)<<31) | (stream_id & 0xfff),
-                              0x80000fff);
+            ret = _select_pg_textst_stream(bd, stream_id, enable_flag, 
is_checked_uo_mask);
             break;
         /*
         case BLURAY_SECONDARY_VIDEO_STREAM:
@@ -3081,6 +3202,8 @@ void bd_select_stream(BLURAY *bd, uint32_t stream_type, 
uint32_t stream_id, uint
     }
 
     bd_mutex_unlock(&bd->mutex);
+
+    return ret;
 }
 
 /*
@@ -3511,12 +3634,16 @@ static int _try_play_title(BLURAY *bd, unsigned title)
         return 0;
     }
 
-    if (bd->uo_mask.title_search) {
-        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "title search masked\n");
+    if (BLURAY_PLAYER_SETTING_UO_RESTRICTION_RELAXED <= 
bd->uo_restriction_level && bd->uo_mask.title_search) {
+        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_play_title(): UO title search 
masked\n");
+        // FIXME: UO_MASK_TITLE_SEARCH_INDEX is not part of BD-J API 
UOMaskTableControl
         _bdj_event(bd, BDJ_EVENT_UO_MASKED, UO_MASK_TITLE_SEARCH_INDEX);
+
         return 0;
     }
 
+    /* TODO: Check if the title can be accessed */
+
     return _play_title(bd, title);
 }
 
@@ -3544,9 +3671,11 @@ static int _try_menu_call(BLURAY *bd, int64_t pts)
         return 0;
     }
 
-    if (bd->uo_mask.menu_call) {
-        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "menu call masked\n");
+    if (BLURAY_PLAYER_SETTING_UO_RESTRICTION_RELAXED <= 
bd->uo_restriction_level && bd->uo_mask.menu_call) {
+        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_menu_call(): UO menu call 
masked\n");
+        // FIXME: UO_MASK_MENU_CALL_INDEX is not part of BD-J API 
UOMaskTableControl
         _bdj_event(bd, BDJ_EVENT_UO_MASKED, UO_MASK_MENU_CALL_INDEX);
+
         return 0;
     }
 
@@ -3795,12 +3924,50 @@ void bd_set_scr(BLURAY *bd, int64_t pts)
     bd_mutex_unlock(&bd->mutex);
 }
 
+static int _get_rate_uo_index(BLURAY *bd, uint32_t rate, bd_uo_mask_index_e 
*uo_index)
+{
+    if (BLURAY_RATE_PAUSED == rate) {
+        /* Pause On should be a safe UO */
+        if (bd->uo_restriction_level <= 
BLURAY_PLAYER_SETTING_UO_RESTRICTION_SAFE) {
+            return 0; // ignore UO restriction
+        }
+        *uo_index = UO_MASK_PAUSE_ON_MASK_INDEX;
+        return 1;
+    }
+
+    /* If current clip is freezed, Still Off UO will certainly break playback 
*/
+    if (bd->st0.clip->still_mode >= BLURAY_STILL_TIME) {
+        if (bd->uo_restriction_level <= 
BLURAY_PLAYER_SETTING_UO_RESTRICTION_SAFE) {
+            return 0; // ignore UO restriction
+        }
+        *uo_index = UO_MASK_STILL_OFF_MASK_INDEX;
+        return 1;
+    }
+
+    /* use Forward Play UO, as libbluray does not consider backward play */
+    if (bd->uo_restriction_level <= BLURAY_PLAYER_SETTING_UO_RESTRICTION_SAFE) 
{
+        return 0; // ignore UO restriction
+    }
+
+    *uo_index = UO_MASK_FORWARD_PLAY_MASK_INDEX;
+    return 1;
+}
+
 static int _set_rate(BLURAY *bd, uint32_t rate)
 {
+    bd_uo_mask_index_e uo_mask_idx = 0;
+
     if (!bd->title) {
         return -1;
     }
 
+    if (_get_rate_uo_index(bd, rate, &uo_mask_idx) && _is_uo_masked(bd, 
uo_mask_idx)) {
+        BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_set_rate(%" PRIu32 ") UO %d 
restricted\n",
+            rate, uo_mask_idx);
+        _bdj_event(bd, BDJ_EVENT_UO_MASKED, (unsigned) uo_mask_idx);
+        return -1;
+    }
+
     if (bd->title_type == title_bdj) {
         return _bdj_event(bd, BDJ_EVENT_RATE, rate);
     }
@@ -3839,6 +4006,47 @@ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, 
uint16_t y)
     return result;
 }
 
+static int _get_key_uo_index(BLURAY *bd, uint32_t key_id, bd_uo_mask_index_e 
*uo_index)
+{
+    unsigned i;
+
+    static const struct {
+        bd_vk_key_e key;
+        bd_uo_mask_index_e uo_index;
+        bd_player_setting_uo_restriction_level uo_min_level;
+    } key_uo_map[] = {
+#define D(k, i, l)  { k, UO_MASK_ ## i, BLURAY_PLAYER_SETTING_UO_RESTRICTION_ 
## l }
+        D(BD_VK_ROOT_MENU, MENU_CALL_INDEX, SAFE),
+        /* BD_VK_POPUP handled specifically */
+        D(BD_VK_UP, MOVE_UP_SELECTED_BUTTON_MASK_INDEX, COMPLIANT),
+        D(BD_VK_DOWN, MOVE_DOWN_SELECTED_BUTTON_MASK_INDEX, COMPLIANT),
+        D(BD_VK_LEFT, MOVE_LEFT_SELECTED_BUTTON_MASK_INDEX, COMPLIANT),
+        D(BD_VK_RIGHT, MOVE_RIGHT_SELECTED_BUTTON_MASK_INDEX, COMPLIANT),
+        D(BD_VK_ENTER, ACTIVATE_BUTTON_MASK_INDEX, COMPLIANT),
+#undef D
+    };
+
+    if (BD_VK_POPUP == key_id) {
+        /* check if pop-up menu is on, if so key is treated as Pop-up Off UO */
+        if (bd->uo_restriction_level <= 
BLURAY_PLAYER_SETTING_UO_RESTRICTION_SAFE) {
+            return 0; // Not enforced
+        }
+        return (bd->gc_status & GC_STATUS_POPUP) ? 
UO_MASK_POPUP_OFF_MASK_INDEX : UO_MASK_POPUP_ON_MASK_INDEX;
+    }
+
+    for (i = 0; i < sizeof(key_uo_map) / sizeof(key_uo_map[0]); i++) {
+        if (key_uo_map[i].key == key_id) {
+            if (bd->uo_restriction_level < key_uo_map[i].uo_min_level) {
+                return 0; // Not enforced
+            }
+            *uo_index = key_uo_map[i].uo_index;
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 #define BD_VK_FLAGS_MASK (BD_VK_KEY_PRESSED | BD_VK_KEY_TYPED | 
BD_VK_KEY_RELEASED)
 #define BD_VK_KEY(k)     ((k) & ~(BD_VK_FLAGS_MASK))
 #define BD_VK_FLAGS(k)   ((k) & BD_VK_FLAGS_MASK)
@@ -3847,6 +4055,8 @@ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, 
uint16_t y)
 
 int bd_user_input(BLURAY *bd, int64_t pts, uint32_t key)
 {
+    bd_uo_mask_index_e uo_mask_idx = 0;
+    int uo_is_masked = 0;
     int result = -1;
 
     if (BD_VK_KEY(key) == BD_VK_ROOT_MENU) {
@@ -3859,10 +4069,18 @@ int bd_user_input(BLURAY *bd, int64_t pts, uint32_t key)
     bd_mutex_lock(&bd->mutex);
 
     _set_scr(bd, pts);
+    if (_get_key_uo_index(bd, BD_VK_KEY(key), &uo_mask_idx)) {
+        uo_is_masked = _is_uo_masked(bd, uo_mask_idx);
+    }
 
     if (bd->title_type == title_hdmv) {
         if (BD_KEY_TYPED(key)) {
-            result = _run_gc(bd, GC_CTRL_VK_KEY, BD_VK_KEY(key));
+            if (uo_is_masked) {
+                BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_user_input(%" PRIu32 ") UO 
%d restricted\n", key, uo_mask_idx);
+                result = 0;
+            } else {
+                result = _run_gc(bd, GC_CTRL_VK_KEY, BD_VK_KEY(key));
+            }
         } else {
             result = 0;
         }


=====================================
src/libbluray/bluray.h
=====================================
@@ -535,7 +535,8 @@ BD_PUBLIC int bd_read(BLURAY *bd, unsigned char *buf, int 
len);
  */
 
 /**
- *  Seek to pos in currently selected title
+ *
+ *  Seek to pos in currently selected title.
  *
  * @param bd  BLURAY object
  * @param pos position to seek to
@@ -545,21 +546,26 @@ BD_PUBLIC int64_t bd_seek(BLURAY *bd, uint64_t pos);
 
 /**
  *
- * Seek to specific time in 90Khz ticks
+ *  Seek to specific time in 90Khz ticks.
  *
- * @param bd    BLURAY ojbect
- * @param tick  tick count
- * @return current seek position
+ *  May fail if UO mask bit BLURAY_UO_TIME_SEARCH_MASK is set.
+ *
+ * @param bd  BLURAY object
+ * @param tick tick count
+ * @return <0 on UO mask restriction, current seek position otherwise
  */
 BD_PUBLIC int64_t bd_seek_time(BLURAY *bd, uint64_t tick);
 
 /**
  *
- *  Seek to a chapter. First chapter is 0
+ *  Seek to a chapter.
+ *
+ *  First chapter is 0.
+ *  May fail if UO mask bit BLURAY_UO_CHAPTER_SEARCH is set.
  *
  * @param bd  BLURAY object
  * @param chapter chapter to seek to
- * @return current seek position
+ * @return <0 on UO mask restriction, current seek position otherwise
  */
 BD_PUBLIC int64_t bd_seek_chapter(BLURAY *bd, unsigned chapter);
 
@@ -585,7 +591,9 @@ BD_PUBLIC int64_t bd_seek_playitem(BLURAY *bd, unsigned 
clip_ref);
 
 /**
  *
- *  Set the angle to play
+ *  Set the angle to play.
+ *
+ *  May fail if UO mask bit UO_MASK_ANGLE_CHANGE_MASK_INDEX is set.
  *
  * @param bd  BLURAY object
  * @param angle angle to play
@@ -619,12 +627,22 @@ BD_PUBLIC void bd_seamless_angle_change(BLURAY *bd, 
unsigned angle);
  *  Without on-disc menus selecting the stream is useful only when using
  *  libbluray internal decoders or the stream is stored in a sub-path.
  *
+ *  Depending on stream type, may fail if one of the following UO mask bit is 
set:
+ *    - UO_MASK_PRIMARY_AUDIO_CHANGE_MASK_INDEX (BLURAY_AUDIO_STREAM);
+ *    - UO_MASK_PG_TEXTST_ENABLE_DISABLE_MASK_INDEX (BLURAY_PG_TEXTST_STREAM);
+ *    - UO_MASK_PG_TEXTST_CHANGE_MASK_INDEX (BLURAY_PG_TEXTST_STREAM);
+ *  or if the requested stream number is out of range. If multiple changes are
+ *  made (e.g. enable and change PG/TextST track), the non-masked UOs are
+ *  applied (but this function might still return 0 if at least one change was
+ *  prohibited).
+ *
  * @param bd  BLURAY object
  * @param stream_type  BLURAY_AUDIO_STREAM or BLURAY_PG_TEXTST_STREAM
  * @param stream_id  stream number (1..N)
  * @param enable_flag  set to 0 to disable streams of this type
+ * @return <0 on error, 1 if the stream was selected, 0 if no change was made, 
or was prevented by the UO mask
  */
-BD_PUBLIC void bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t 
stream_id, uint32_t enable_flag);
+BD_PUBLIC int bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t 
stream_id, uint32_t enable_flag);
 
 #define BLURAY_AUDIO_STREAM      0   /**< Select audio stream     */
 #define BLURAY_PG_TEXTST_STREAM  1   /**< Select subtitle stream  */
@@ -720,9 +738,9 @@ typedef enum {
     BLURAY_PLAYER_SETTING_PERSISTENT_STORAGE   = 0x101, /**< Enable/disable 
BD-J persistent storage. Integer. Default: enabled. */
     BLURAY_PLAYER_SETTING_UO_RESTRICTION_LEVEL = 0x102, /**< Set User 
Operations (UO) restriction mask enforcement level. 
bd_player_setting_uo_restriction_level value. Default: 
BLURAY_PLAYER_SETTING_UO_RESTRICTION_RELAXED. */
 
-    BLURAY_PLAYER_PERSISTENT_ROOT            = 0x200, /**< Root path to the 
BD_J persistent storage location. String. */
-    BLURAY_PLAYER_CACHE_ROOT                 = 0x201, /**< Root path to the 
BD_J cache storage location. String. */
-    BLURAY_PLAYER_JAVA_HOME                  = 0x202, /**< Location of JRE. 
String. Default: NULL (autodetect). */
+    BLURAY_PLAYER_PERSISTENT_ROOT              = 0x200, /**< Root path to the 
BD_J persistent storage location. String. */
+    BLURAY_PLAYER_CACHE_ROOT                   = 0x201, /**< Root path to the 
BD_J cache storage location. String. */
+    BLURAY_PLAYER_JAVA_HOME                    = 0x202, /**< Location of JRE. 
String. Default: NULL (autodetect). */
 } bd_player_setting;
 
 /** Player User Operation (UO) restriction mask enforcement level. */
@@ -1034,6 +1052,7 @@ BD_PUBLIC int  bd_play_title(BLURAY *bd, unsigned title);
  *  Open BluRay disc Top Menu.
  *
  *  Current pts is needed for resuming playback when menu is closed.
+ *  May fail if UO mask bit BLURAY_UO_MENU_CALL is set.
  *
  * @param bd  BLURAY object
  * @param pts current playback position (1/90000s) or -1
@@ -1128,6 +1147,16 @@ BD_PUBLIC int bd_set_rate(BLURAY *bd, uint32_t rate);
  *    - Separate events when key is pressed and released.
  *      VD_VK_KEY_PRESSED, BD_VK_TYPED and BD_VK_KEY_RELEASED are or'd with 
the key.
  *
+ *  Depending on the action, may fail if one of the following UO mask bit is 
set:
+ *    - UO_MASK_MENU_CALL_INDEX (BD_VK_ROOT_MENU);
+ *    - UO_MASK_MOVE_UP_SELECTED_BUTTON_MASK_INDEX (BD_VK_UP);
+ *    - UO_MASK_MOVE_DOWN_SELECTED_BUTTON_MASK_INDEX (BD_VK_DOWN);
+ *    - UO_MASK_MOVE_LEFT_SELECTED_BUTTON_MASK_INDEX (BD_VK_LEFT);
+ *    - UO_MASK_MOVE_RIGHT_SELECTED_BUTTON_MASK_INDEX (BD_VK_RIGHT);
+ *    - UO_MASK_ACTIVATE_BUTTON_MASK_INDEX (BD_VK_ENTER);
+ *    - UO_MASK_POPUP_ON_MASK_INDEX (BD_VK_POPUP);
+ *    - UO_MASK_POPUP_OFF_MASK_INDEX (BD_VK_POPUP);
+ *
  * @param bd  BLURAY object
  * @param pts current playback position (1/90000s) or -1
  * @param key input key (@see keys.h)



View it on GitLab: 
https://code.videolan.org/videolan/libbluray/-/commit/4c785b60d70492ef7b682cbc6f8d11ed62233b8e

-- 
View it on GitLab: 
https://code.videolan.org/videolan/libbluray/-/commit/4c785b60d70492ef7b682cbc6f8d11ed62233b8e
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance
_______________________________________________
libbluray-devel mailing list
[email protected]
https://mailman.videolan.org/listinfo/libbluray-devel

Reply via email to