482 lines
18 KiB
Go
482 lines
18 KiB
Go
package bluray
|
|
|
|
/*
|
|
#cgo pkg-config: libbluray
|
|
#include <libbluray/bluray.h>
|
|
#include <stdlib.h>
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
func GetBDVersion() string {
|
|
var major, minor, micro C.int
|
|
C.bd_get_version(&major, &minor, µ)
|
|
return fmt.Sprintf("%d.%d.%d", int(major), int(minor), int(micro))
|
|
}
|
|
|
|
type DBStruct struct {
|
|
bd *C.BLURAY
|
|
}
|
|
|
|
// BDOpen 打开蓝光光盘
|
|
func BDOpen(path string) (*DBStruct, error) {
|
|
// 检查文件路径是否存在文件或者文件夹
|
|
if _, err := os.Stat(path); err != nil {
|
|
return nil, fmt.Errorf("file not found: %v", err)
|
|
}
|
|
cPath := C.CString(path)
|
|
defer C.free(unsafe.Pointer(cPath))
|
|
|
|
return &DBStruct{bd: C.bd_open(cPath, nil)}, nil
|
|
}
|
|
|
|
// GetDiscInfo 获取蓝光光盘信息
|
|
// const BlurayDiscInfo *bd_get_disc_info(BLURAY *bd);
|
|
func (d *DBStruct) GetDiscInfo() (*BlurayDiscInfo, error) {
|
|
cInfo := C.bd_get_disc_info(d.bd) // 调用 C 函数获取 BluRay 光盘信息
|
|
|
|
convertCToGoTitle := func(cTitle *C.BLURAY_TITLE) *BlurayTitle {
|
|
if cTitle == nil {
|
|
return nil
|
|
}
|
|
return &BlurayTitle{
|
|
Name: cStringToGoString(cTitle.name),
|
|
Interactive: uint8(cTitle.interactive),
|
|
Accessible: uint8(cTitle.accessible),
|
|
Hidden: uint8(cTitle.hidden),
|
|
BDJ: uint8(cTitle.bdj),
|
|
IDRef: uint32(cTitle.id_ref),
|
|
}
|
|
}
|
|
|
|
if cInfo == nil {
|
|
return nil, fmt.Errorf("failed to get disc info")
|
|
}
|
|
|
|
// 转换 Titles 数组
|
|
var goTitles []*BlurayTitle
|
|
if cInfo.num_titles > 0 && cInfo.titles != nil {
|
|
// 遍历 C 数组,转换每个 BLURAY_TITLE
|
|
cTitles := (*[1 << 30]*C.BLURAY_TITLE)(unsafe.Pointer(cInfo.titles))[:cInfo.num_titles:cInfo.num_titles]
|
|
for _, cTitle := range cTitles {
|
|
goTitles = append(goTitles, convertCToGoTitle(cTitle))
|
|
}
|
|
}
|
|
|
|
goInfo := &BlurayDiscInfo{
|
|
BlurayDetected: uint8(cInfo.bluray_detected),
|
|
DiscName: cStringToGoString(cInfo.disc_name),
|
|
UDFVolumeID: cStringToGoString(cInfo.udf_volume_id),
|
|
DiscID: *(*[20]byte)(unsafe.Pointer(&cInfo.disc_id)),
|
|
NoMenuSupport: uint8(cInfo.no_menu_support),
|
|
FirstPlaySupported: uint8(cInfo.first_play_supported),
|
|
TopMenuSupported: uint8(cInfo.top_menu_supported),
|
|
NumTitles: uint32(cInfo.num_titles),
|
|
Titles: goTitles,
|
|
FirstPlay: convertCToGoTitle(cInfo.first_play),
|
|
TopMenu: convertCToGoTitle(cInfo.top_menu),
|
|
NumHDMVTitles: uint32(cInfo.num_hdmv_titles),
|
|
NumBDJTitles: uint32(cInfo.num_bdj_titles),
|
|
NumUnsupportedTitles: uint32(cInfo.num_unsupported_titles),
|
|
BDJDetected: uint8(cInfo.bdj_detected),
|
|
BDJSupported: uint8(cInfo.bdj_supported),
|
|
LibJVMDetected: uint8(cInfo.libjvm_detected),
|
|
BDJHandled: uint8(cInfo.bdj_handled),
|
|
BDJOrgID: *(*[9]byte)(unsafe.Pointer(&cInfo.bdj_org_id)),
|
|
BDJDiscID: *(*[33]byte)(unsafe.Pointer(&cInfo.bdj_disc_id)),
|
|
VideoFormat: uint8(cInfo.video_format),
|
|
FrameRate: uint8(cInfo.frame_rate),
|
|
ContentExist3D: uint8(cInfo.content_exist_3D),
|
|
InitialOutputModePreference: uint8(cInfo.initial_output_mode_preference),
|
|
ProviderData: *(*[32]byte)(unsafe.Pointer(&cInfo.provider_data)),
|
|
AACDetected: uint8(cInfo.aacs_detected),
|
|
LibAACSDetected: uint8(cInfo.libaacs_detected),
|
|
AACSHandled: uint8(cInfo.aacs_handled),
|
|
AACSErrorCode: int(cInfo.aacs_error_code),
|
|
AACSMKBV: int(cInfo.aacs_mkbv),
|
|
BDPlusDetected: uint8(cInfo.bdplus_detected),
|
|
LibBDPlusDetected: uint8(cInfo.libbdplus_detected),
|
|
BDPlusHandled: uint8(cInfo.bdplus_handled),
|
|
BDPlusGen: uint8(cInfo.bdplus_gen),
|
|
BDPlusDate: uint32(cInfo.bdplus_date),
|
|
InitialDynamicRangeType: uint8(cInfo.initial_dynamic_range_type),
|
|
}
|
|
|
|
return goInfo, nil
|
|
}
|
|
|
|
// GetMetaFile 获取蓝光光盘的元数据文件
|
|
|
|
const (
|
|
TitlesAll = 0
|
|
TitlesFilterDupTitle = 0x01
|
|
TitlesFilterDupClip = 0x02
|
|
TitlesRelevant = TitlesFilterDupTitle | TitlesFilterDupClip
|
|
)
|
|
|
|
// GetTitles 获取标题数量(播放列表)
|
|
// GetTitles Get the number of titles (playlists) on the disc
|
|
func (d *DBStruct) GetTitles(flags uint8, minTitleLength uint32) (uint32, error) {
|
|
numTitles := C.bd_get_titles(d.bd, C.uint8_t(flags), C.uint32_t(minTitleLength))
|
|
if numTitles == 0 {
|
|
return 0, fmt.Errorf("failed to get titles or no titles found")
|
|
}
|
|
return uint32(numTitles), nil
|
|
}
|
|
|
|
// GetMainTitle 获取主标题
|
|
// GetMainTitle Get the main title
|
|
func (d *DBStruct) GetMainTitle() (uint32, error) {
|
|
mainTitle := C.bd_get_main_title(d.bd)
|
|
if mainTitle == 0 {
|
|
return 0, fmt.Errorf("failed to get main title")
|
|
}
|
|
return uint32(mainTitle), nil
|
|
}
|
|
|
|
// GetTitleInfo 从蓝光光盘获取标题信息 需要先调用 GetTitles() 获取标题列表
|
|
// GetTitleInfo Get title info from a Blu-ray disc. GetTitles() must be called first to get the title list
|
|
func (d *DBStruct) GetTitleInfo(titleIdx uint32, angle uint) (*BlurayTitleInfo, error) {
|
|
cTitleInfo := C.bd_get_title_info(d.bd, C.uint32_t(titleIdx), C.uint(angle))
|
|
if cTitleInfo == nil {
|
|
return nil, fmt.Errorf("failed to get title info")
|
|
}
|
|
defer C.bd_free_title_info(cTitleInfo)
|
|
|
|
titleInfo := &BlurayTitleInfo{
|
|
Idx: uint32(cTitleInfo.idx),
|
|
Playlist: uint32(cTitleInfo.playlist),
|
|
Duration: uint64(cTitleInfo.duration),
|
|
ClipCount: uint32(cTitleInfo.clip_count),
|
|
AngleCount: uint8(cTitleInfo.angle_count),
|
|
ChapterCount: uint32(cTitleInfo.chapter_count),
|
|
MarkCount: uint32(cTitleInfo.mark_count),
|
|
MvcBaseViewRFlag: uint8(cTitleInfo.mvc_base_view_r_flag),
|
|
}
|
|
|
|
if cTitleInfo.clip_count > 0 && cTitleInfo.clips != nil {
|
|
titleInfo.Clips = make([]BlurayClipInfo, cTitleInfo.clip_count)
|
|
cClipsSlice := (*[1 << 30]C.BLURAY_CLIP_INFO)(unsafe.Pointer(cTitleInfo.clips))[:cTitleInfo.clip_count:cTitleInfo.clip_count]
|
|
|
|
for i := 0; i < int(cTitleInfo.clip_count); i++ {
|
|
cClip := cClipsSlice[i]
|
|
|
|
clipIdStr := C.GoStringN(&cClip.clip_id[0], 5)
|
|
clipIdStr = strings.TrimLeft(clipIdStr, "0") // Remove leading zeros
|
|
if clipIdStr == "" {
|
|
clipIdStr = "0"
|
|
}
|
|
clipId, err := strconv.ParseUint(clipIdStr, 10, 32)
|
|
if err != nil {
|
|
clipId = 0
|
|
}
|
|
|
|
clipInfo := BlurayClipInfo{
|
|
PktCount: uint32(cClip.pkt_count),
|
|
StillMode: getStillModeString(cClip.still_mode),
|
|
StillTime: uint16(cClip.still_time),
|
|
VideoStreamCount: uint8(cClip.video_stream_count),
|
|
AudioStreamCount: uint8(cClip.audio_stream_count),
|
|
PgStreamCount: uint8(cClip.pg_stream_count),
|
|
IgStreamCount: uint8(cClip.ig_stream_count),
|
|
SecAudioStreamCount: uint8(cClip.sec_audio_stream_count),
|
|
SecVideoStreamCount: uint8(cClip.sec_video_stream_count),
|
|
StartTime: uint64(cClip.start_time),
|
|
InTime: uint64(cClip.in_time),
|
|
OutTime: uint64(cClip.out_time),
|
|
ClipId: uint(clipId), // Assign the parsed ClipId
|
|
}
|
|
|
|
if cClip.video_stream_count > 0 && cClip.video_streams != nil {
|
|
clipInfo.VideoStreams = make([]BlurayStreamInfo, cClip.video_stream_count)
|
|
cVideoStreams := (*[1 << 30]C.BLURAY_STREAM_INFO)(unsafe.Pointer(cClip.video_streams))[:cClip.video_stream_count:cClip.video_stream_count]
|
|
|
|
for j := 0; j < int(cClip.video_stream_count); j++ {
|
|
cStream := cVideoStreams[j]
|
|
lang := getLanguageCode(cStream.lang)
|
|
streamInfo := BlurayStreamInfo{
|
|
CodingType: getCodingString(cStream.coding_type),
|
|
Format: getVideoFormatString(cStream.format),
|
|
Rate: getVideoRateString(cStream.rate),
|
|
CharCode: uint8(cStream.char_code),
|
|
Pid: uint16(cStream.pid),
|
|
Aspect: getAspectRatioString(cStream.aspect),
|
|
SubpathId: uint8(cStream.subpath_id),
|
|
Lang: lang,
|
|
}
|
|
clipInfo.VideoStreams[j] = streamInfo
|
|
}
|
|
}
|
|
|
|
if cClip.audio_stream_count > 0 && cClip.audio_streams != nil {
|
|
clipInfo.AudioStreams = make([]BlurayStreamInfo, cClip.audio_stream_count)
|
|
cAudioStreams := (*[1 << 30]C.BLURAY_STREAM_INFO)(unsafe.Pointer(cClip.audio_streams))[:cClip.audio_stream_count:cClip.audio_stream_count]
|
|
|
|
for j := 0; j < int(cClip.audio_stream_count); j++ {
|
|
cStream := cAudioStreams[j]
|
|
lang := getLanguageCode(cStream.lang)
|
|
streamInfo := BlurayStreamInfo{
|
|
CodingType: getCodingString(cStream.coding_type),
|
|
Format: getAudioFormatString(cStream.format),
|
|
Rate: getAudioRateString(cStream.rate),
|
|
CharCode: uint8(cStream.char_code),
|
|
Pid: uint16(cStream.pid),
|
|
SubpathId: uint8(cStream.subpath_id),
|
|
Lang: lang,
|
|
}
|
|
clipInfo.AudioStreams[j] = streamInfo
|
|
}
|
|
}
|
|
|
|
if cClip.pg_stream_count > 0 && cClip.pg_streams != nil {
|
|
clipInfo.PgStreams = make([]BlurayStreamInfo, cClip.pg_stream_count)
|
|
cPgStreams := (*[1 << 30]C.BLURAY_STREAM_INFO)(unsafe.Pointer(cClip.pg_streams))[:cClip.pg_stream_count:cClip.pg_stream_count]
|
|
|
|
for j := 0; j < int(cClip.pg_stream_count); j++ {
|
|
cStream := cPgStreams[j]
|
|
streamInfo := BlurayStreamInfo{
|
|
CodingType: getCodingString(cStream.coding_type),
|
|
Pid: uint16(cStream.pid),
|
|
SubpathId: uint8(cStream.subpath_id),
|
|
Lang: C.GoStringN((*C.char)(unsafe.Pointer(&cStream.lang[0])), 3),
|
|
}
|
|
clipInfo.PgStreams[j] = streamInfo
|
|
}
|
|
}
|
|
|
|
if cClip.ig_stream_count > 0 && cClip.ig_streams != nil {
|
|
clipInfo.IgStreams = make([]BlurayStreamInfo, cClip.ig_stream_count)
|
|
cIgStreams := (*[1 << 30]C.BLURAY_STREAM_INFO)(unsafe.Pointer(cClip.ig_streams))[:cClip.ig_stream_count:cClip.ig_stream_count]
|
|
|
|
for j := 0; j < int(cClip.ig_stream_count); j++ {
|
|
cStream := cIgStreams[j]
|
|
streamInfo := BlurayStreamInfo{
|
|
CodingType: getCodingString(cStream.coding_type),
|
|
Pid: uint16(cStream.pid),
|
|
SubpathId: uint8(cStream.subpath_id),
|
|
Lang: C.GoStringN((*C.char)(unsafe.Pointer(&cStream.lang[0])), 3),
|
|
}
|
|
clipInfo.IgStreams[j] = streamInfo
|
|
}
|
|
}
|
|
|
|
if cClip.sec_audio_stream_count > 0 && cClip.sec_audio_streams != nil {
|
|
clipInfo.SecAudioStreams = make([]BlurayStreamInfo, cClip.sec_audio_stream_count)
|
|
cSecAudioStreams := (*[1 << 30]C.BLURAY_STREAM_INFO)(unsafe.Pointer(cClip.sec_audio_streams))[:cClip.sec_audio_stream_count:cClip.sec_audio_stream_count]
|
|
|
|
for j := 0; j < int(cClip.sec_audio_stream_count); j++ {
|
|
cStream := cSecAudioStreams[j]
|
|
streamInfo := BlurayStreamInfo{
|
|
CodingType: getCodingString(cStream.coding_type),
|
|
Format: getAudioFormatString(cStream.format),
|
|
Rate: getAudioRateString(cStream.rate),
|
|
Pid: uint16(cStream.pid),
|
|
SubpathId: uint8(cStream.subpath_id),
|
|
Lang: C.GoStringN((*C.char)(unsafe.Pointer(&cStream.lang[0])), 3),
|
|
}
|
|
clipInfo.SecAudioStreams[j] = streamInfo
|
|
}
|
|
}
|
|
|
|
if cClip.sec_video_stream_count > 0 && cClip.sec_video_streams != nil {
|
|
clipInfo.SecVideoStreams = make([]BlurayStreamInfo, cClip.sec_video_stream_count)
|
|
cSecVideoStreams := (*[1 << 30]C.BLURAY_STREAM_INFO)(unsafe.Pointer(cClip.sec_video_streams))[:cClip.sec_video_stream_count:cClip.sec_video_stream_count]
|
|
|
|
for j := 0; j < int(cClip.sec_video_stream_count); j++ {
|
|
cStream := cSecVideoStreams[j]
|
|
streamInfo := BlurayStreamInfo{
|
|
CodingType: getCodingString(cStream.coding_type),
|
|
Format: getVideoFormatString(cStream.format),
|
|
Rate: getVideoRateString(cStream.rate),
|
|
CharCode: uint8(cStream.char_code),
|
|
Pid: uint16(cStream.pid),
|
|
Aspect: getAspectRatioString(cStream.aspect),
|
|
SubpathId: uint8(cStream.subpath_id),
|
|
Lang: C.GoStringN((*C.char)(unsafe.Pointer(&cStream.lang[0])), 3),
|
|
}
|
|
clipInfo.SecVideoStreams[j] = streamInfo
|
|
}
|
|
}
|
|
|
|
titleInfo.Clips[i] = clipInfo
|
|
}
|
|
}
|
|
|
|
if cTitleInfo.chapter_count > 0 && cTitleInfo.chapters != nil {
|
|
titleInfo.Chapters = make([]BlurayTitleChapter, cTitleInfo.chapter_count)
|
|
cChapters := (*[1 << 30]C.BLURAY_TITLE_CHAPTER)(unsafe.Pointer(cTitleInfo.chapters))[:cTitleInfo.chapter_count:cTitleInfo.chapter_count]
|
|
|
|
for i := 0; i < int(cTitleInfo.chapter_count); i++ {
|
|
cChapter := cChapters[i]
|
|
chapter := BlurayTitleChapter{
|
|
Idx: uint32(cChapter.idx),
|
|
Start: uint64(cChapter.start),
|
|
Duration: uint64(cChapter.duration),
|
|
Offset: uint64(cChapter.offset),
|
|
ClipRef: uint(cChapter.clip_ref),
|
|
}
|
|
titleInfo.Chapters[i] = chapter
|
|
}
|
|
}
|
|
|
|
if cTitleInfo.mark_count > 0 && cTitleInfo.marks != nil {
|
|
titleInfo.Marks = make([]BlurayTitleMark, cTitleInfo.mark_count)
|
|
cMarks := (*[1 << 30]C.BLURAY_TITLE_MARK)(unsafe.Pointer(cTitleInfo.marks))[:cTitleInfo.mark_count:cTitleInfo.mark_count]
|
|
|
|
for i := 0; i < int(cTitleInfo.mark_count); i++ {
|
|
cMark := cMarks[i]
|
|
mark := BlurayTitleMark{
|
|
Idx: uint32(cMark.idx),
|
|
Type: int(cMark._type), // Use _type because 'type' is a reserved keyword in Go
|
|
Start: uint64(cMark.start),
|
|
Duration: uint64(cMark.duration),
|
|
Offset: uint64(cMark.offset),
|
|
ClipRef: uint(cMark.clip_ref),
|
|
}
|
|
titleInfo.Marks[i] = mark
|
|
}
|
|
}
|
|
|
|
return titleInfo, nil
|
|
}
|
|
|
|
//// SelectTitle 从 GetTitles() 创建的列表中选择标题
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SelectTitle(titleIdx uint32) (int, error) {
|
|
// result := C.bd_select_title(d.bd, C.uint32_t(titleIdx))
|
|
// if result != 0 {
|
|
// return 0, fmt.Errorf("failed to select title")
|
|
// }
|
|
// return int(result), nil
|
|
//}
|
|
//
|
|
//// SelectPlaylist 选择播放列表
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SelectPlaylist(playlistIdx uint32) (int, error) {
|
|
// result := C.bd_select_playlist(d.bd, C.uint32_t(playlistIdx))
|
|
// if result != 0 {
|
|
// return 0, fmt.Errorf("failed to select playlist")
|
|
// }
|
|
// return int(result), nil
|
|
//}
|
|
//
|
|
//// GetCurrentTitle 获取当前标题
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) GetCurrentTitle() (uint32, error) {
|
|
// result := C.bd_get_current_title(d.bd)
|
|
// if result == 0 {
|
|
// return 0, fmt.Errorf("failed to get current title")
|
|
// }
|
|
// return uint32(result), nil
|
|
//}
|
|
|
|
//// Read Read from currently selected title file, decrypt if possible
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) Read() (int, error) {
|
|
// result := C.bd_read(d.bd)
|
|
// if result != 0 {
|
|
// return 0, fmt.Errorf("failed to read")
|
|
// }
|
|
// return int(result), nil
|
|
//}
|
|
|
|
//// Seek Seek to a position in the currently selected title file
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) Seek(pos uint64) (int64, error) {
|
|
// result := C.bd_seek(d.bd, C.uint64_t(pos))
|
|
// return int64(result), nil
|
|
//}
|
|
//
|
|
//// SeekTime Seek to a time in the currently selected title file
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SeekTime(tick uint64) (int64, error) {
|
|
// result := C.bd_seek_time(d.bd, C.uint64_t(tick))
|
|
// return int64(result), nil
|
|
//}
|
|
//
|
|
//// SeekChapter Seek to a chapter in the currently selected title file
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SeekChapter(chapter uint) (int64, error) {
|
|
// result := C.bd_seek_chapter(d.bd, C.uint(chapter))
|
|
// return int64(result), nil
|
|
//}
|
|
//
|
|
//// SeekMark Seek to a mark in the currently selected title file
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SeekMark(mark uint) (int64, error) {
|
|
// result := C.bd_seek_mark(d.bd, C.uint(mark))
|
|
// return int64(result), nil
|
|
//}
|
|
//
|
|
//// SeekPlayitem Seek to a playitem in the currently selected title file
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SeekPlayitem(clipRef uint) (int64, error) {
|
|
// result := C.bd_seek_playitem(d.bd, C.uint(clipRef))
|
|
// return int64(result), nil
|
|
//}
|
|
//
|
|
//// SelectAngle Set the angle to play
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SelectAngle(angle uint) (int, error) {
|
|
// result := C.bd_select_angle(d.bd, C.uint(angle))
|
|
// if result != 0 {
|
|
// return 0, fmt.Errorf("failed to select angle")
|
|
// }
|
|
// return int(result), nil
|
|
//}
|
|
//
|
|
//// SeamlessAngleChange Change the angle without stopping playback
|
|
//// [未测试] 由copilot生成的代码
|
|
//// [NotTested] Code generated by copilot
|
|
//func (d *DBStruct) SeamlessAngleChange(angle uint) {
|
|
// C.bd_seamless_angle_change(d.bd, C.uint(angle))
|
|
//}
|
|
//
|
|
//// SelectStream
|
|
///**
|
|
// *
|
|
// * Select stream (PG / TextST track)
|
|
// *
|
|
// * When playing with on-disc menus:
|
|
// *
|
|
// * Stream selection is controlled by on-disc menus.
|
|
// * If user can change stream selection also in player GUI, this function
|
|
// * should be used to keep on-disc menus in sync with player GUI.
|
|
// *
|
|
// * When playing the disc without on-disc menus:
|
|
// *
|
|
// * Initial stream selection is done using preferred language settings.
|
|
// * This function can be used to override automatic stream selection.
|
|
// * Without on-disc menus selecting the stream is useful only when using
|
|
// * libbluray internal decoders or the stream is stored in a sub-path.
|
|
// *
|
|
// * @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
|
|
// */
|
|
//func (d *DBStruct) SelectStream(streamType uint32, streamID uint32, enableFlag uint32) {
|
|
// C.bd_select_stream(d.bd, C.uint32_t(streamType), C.uint32_t(streamID), C.uint32_t(enableFlag))
|
|
//}
|
|
//
|
|
//// Close 关闭蓝光光盘
|
|
//func (d *DBStruct) Close() {
|
|
// C.bd_close(d.bd)
|
|
//}
|