This commit is contained in:
2024-09-16 20:24:30 +08:00
parent c3ed9a2b53
commit f4555c21e5
6 changed files with 723 additions and 1 deletions

View File

@@ -1,2 +1,5 @@
# bluray libbluray的go封装 只支持了部分接口
私人使用的库 只测试了其中的部分接口
The Go wrapper for libbluray only supports a subset of the interfaces
This is a private library, and only some of the interfaces have been tested

62
bluray_test.go Normal file
View File

@@ -0,0 +1,62 @@
package bluray
import (
"encoding/json"
"fmt"
"testing"
)
func TestGetBDVersion(t *testing.T) {
version := GetBDVersion()
if version == "" {
t.Errorf("Expected non-empty version string, got empty string")
}
fmt.Printf("libbluray version: %s\n", version)
}
func TestBD(t *testing.T) {
db := BDOpen("path")
if db == nil {
t.Errorf("Expected non-nil DBStruct, got nil")
return
}
info, err := db.GetDiscInfo()
if err != nil {
t.Errorf("Expected non-nil BlurayDiscInfo, got nil")
return
}
res, err := json.Marshal(info)
if err != nil {
t.Errorf("json.Marshal failed: %v", err)
return
}
fmt.Println(string(res))
num, err := db.GetTitles(TitlesAll, 0)
if err != nil {
t.Errorf("Expected non-nil BlurayTitle, got nil")
return
}
fmt.Printf("titles: %v\n", num)
mainTitle, err := db.GetMainTitle()
if err != nil {
t.Errorf("Expected non-nil BlurayTitle, got nil")
return
}
fmt.Printf("main title: %v\n", mainTitle)
tInfo, err := db.GetTitleInfo(mainTitle, 0)
if err != nil {
t.Errorf("Expected non-nil BlurayTitle, got nil")
return
}
res, err = json.Marshal(tInfo)
if err != nil {
t.Errorf("json.Marshal failed: %v", err)
return
}
fmt.Println(string(res))
}

1
go.mod Normal file
View File

@@ -0,0 +1 @@
module git.slzz.org/gomod/bluray

487
libbluray.go Normal file
View File

@@ -0,0 +1,487 @@
package bluray
/*
#cgo pkg-config: libbluray
#include <libbluray/bluray.h>
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"strconv"
"strings"
"unsafe"
)
func GetBDVersion() string {
var major, minor, micro C.int
C.bd_get_version(&major, &minor, &micro)
return fmt.Sprintf("%d.%d.%d", int(major), int(minor), int(micro))
}
type DBStruct struct {
bd *C.BLURAY
}
// BDOpen 打开蓝光光盘
func BDOpen(path string) *DBStruct {
cPath := C.CString(path)
defer C.free(unsafe.Pointer(cPath))
return &DBStruct{bd: C.bd_open(cPath, 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 从蓝光光盘获取标题信息 0为全部
// GetTitleInfo Get title info from a Blu-ray disc 0 for all
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: uint8(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: uint8(cStream.coding_type),
Format: uint8(cStream.format),
Rate: uint8(cStream.rate),
CharCode: uint8(cStream.char_code),
Pid: uint16(cStream.pid),
Aspect: uint8(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: uint8(cStream.coding_type),
Format: uint8(cStream.format),
Rate: uint8(cStream.rate),
CharCode: uint8(cStream.char_code),
Pid: uint16(cStream.pid),
Aspect: uint8(cStream.aspect),
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: uint8(cStream.coding_type),
Format: uint8(cStream.format),
Rate: uint8(cStream.rate),
CharCode: uint8(cStream.char_code),
Pid: uint16(cStream.pid),
Aspect: uint8(cStream.aspect),
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: uint8(cStream.coding_type),
Format: uint8(cStream.format),
Rate: uint8(cStream.rate),
CharCode: uint8(cStream.char_code),
Pid: uint16(cStream.pid),
Aspect: uint8(cStream.aspect),
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: uint8(cStream.coding_type),
Format: uint8(cStream.format),
Rate: uint8(cStream.rate),
CharCode: uint8(cStream.char_code),
Pid: uint16(cStream.pid),
Aspect: uint8(cStream.aspect),
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: uint8(cStream.coding_type),
Format: uint8(cStream.format),
Rate: uint8(cStream.rate),
CharCode: uint8(cStream.char_code),
Pid: uint16(cStream.pid),
Aspect: uint8(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)
//}

140
libbluray_type.go Normal file
View File

@@ -0,0 +1,140 @@
package bluray
// BlurayTitle 表示BluRay标题的信息
type BlurayTitle struct {
Name *string // 可选的标题名称,使用首选语言
Interactive uint8 // 如果标题是交互式的值为1在UI中不显示标题长度和播放位置
Accessible uint8 // 如果允许跳转到该标题值为1
Hidden uint8 // 如果在播放期间不显示标题编号值为1
BDJ uint8 // 0表示HDMV标题1表示BD-J标题
IDRef uint32 // 电影对象编号/bdjo文件编号
}
// BlurayDiscInfo 表示BluRay光盘的信息
type BlurayDiscInfo struct {
BlurayDetected uint8 // 如果检测到BluRay光盘值为1
// 光盘ID
DiscName *string // 可选的光盘名称,使用首选语言
UDFVolumeID *string // 可选的UDF卷标符
DiscID [20]byte // 光盘ID
// HDMV / BD-J 标题
NoMenuSupport uint8 // 如果无法通过光盘上的菜单播放该光盘值为1
FirstPlaySupported uint8 // 如果光盘上有First Play标题且可以播放值为1
TopMenuSupported uint8 // 如果光盘上有Top Menu标题且可以播放值为1
NumTitles uint32 // 光盘上的标题数量,不包括"First Play"和"Top Menu"
Titles []*BlurayTitle // 标题数组索引为标题编号1...N
FirstPlay *BlurayTitle // titles[N+1]如果光盘上不存在则为NULL
TopMenu *BlurayTitle // titles[0]如果光盘上不存在则为NULL
NumHDMVTitles uint32 // HDMV标题数量
NumBDJTitles uint32 // BD-J标题数量
NumUnsupportedTitles uint32 // 不支持的标题数量
// BD-J 信息仅当光盘使用BD-J时有效
BDJDetected uint8 // 如果光盘使用BD-J值为1
BDJSupported uint8 // (已弃用)
LibJVMDetected uint8 // 如果找到可用的Java虚拟机值为1
BDJHandled uint8 // 如果找到可用的Java虚拟机和libbluray.jar值为1
BDJOrgID [9]byte // BD-J光盘组织ID
BDJDiscID [33]byte // BD-J光盘ID
// 光盘应用程序信息
VideoFormat uint8 // 视频格式bd_video_format_e
FrameRate uint8 // 帧率bd_video_rate_e
ContentExist3D uint8 // 如果光盘上存在3D内容值为1
InitialOutputModePreference uint8 // 0表示2D1表示3D
ProviderData [32]byte // 内容提供者数据
// AACS 信息仅当光盘使用AACS时有效
AACDetected uint8 // 如果光盘使用AACS加密值为1
LibAACSDetected uint8 // 如果找到可用的AACS解码库值为1
AACSHandled uint8 // 如果光盘使用支持的AACS加密值为1
AACSErrorCode int // AACS错误代码BD_AACS_
AACSMKBV int // AACS MKB版本
// BD+ 信息仅当光盘使用BD+时有效)
BDPlusDetected uint8 // 如果光盘使用BD+加密值为1
LibBDPlusDetected uint8 // 如果找到可用的BD+解码库值为1
BDPlusHandled uint8 // 如果光盘使用支持的BD+加密值为1
BDPlusGen uint8 // BD+内容代码生成
BDPlusDate uint32 // BD+内容代码发布日期 ((year<<16)|(month<<8)|day)
// 光盘应用程序信息libbluray > 1.2.0
InitialDynamicRangeType uint8 // 动态范围类型bd_dynamic_range_type_e
}
type BlurayMetaFile struct {
Data []byte
Size int64
}
type BlurayStreamInfo struct {
CodingType uint8
Format uint8
Rate uint8
CharCode uint8
Lang string
Pid uint16
Aspect uint8
SubpathId uint8
}
type BlurayClipInfo struct {
PktCount uint32
StillMode uint8
StillTime uint16
VideoStreamCount uint8
AudioStreamCount uint8
PgStreamCount uint8
IgStreamCount uint8
SecAudioStreamCount uint8
SecVideoStreamCount uint8
VideoStreams []BlurayStreamInfo
AudioStreams []BlurayStreamInfo
PgStreams []BlurayStreamInfo
IgStreams []BlurayStreamInfo
SecAudioStreams []BlurayStreamInfo
SecVideoStreams []BlurayStreamInfo
StartTime uint64
InTime uint64
OutTime uint64
ClipId uint
}
type BlurayTitleChapter struct {
Idx uint32
Start uint64
Duration uint64
Offset uint64
ClipRef uint
}
type BlurayTitleMark struct {
Idx uint32
Type int
Start uint64
Duration uint64
Offset uint64
ClipRef uint
}
type BlurayTitleInfo struct {
Idx uint32
Playlist uint32
Duration uint64
ClipCount uint32
AngleCount uint8
ChapterCount uint32
MarkCount uint32
Clips []BlurayClipInfo
Chapters []BlurayTitleChapter
Marks []BlurayTitleMark
MvcBaseViewRFlag uint8
}

29
tools.go Normal file
View File

@@ -0,0 +1,29 @@
package bluray
/*
#include <stdint.h>
*/
import "C"
import "unsafe"
func cStringToGoString(cStr *C.char) *string {
if cStr == nil {
return nil
}
str := C.GoString(cStr)
return &str
}
func getLanguageCode(langField [4]C.uint8_t) string {
isEmpty := true
for _, b := range langField {
if b != 0 {
isEmpty = false
break
}
}
if isEmpty {
return "und"
}
return C.GoStringN((*C.char)(unsafe.Pointer(&langField[0])), 3)
}