diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f91ff2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,216 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.publishproj + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[cod] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg diff --git a/README.md b/README.md index 96e6998..00cd9d1 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ -# VapourSynth-ReadMpls \ No newline at end of file +Description +=========== + +Reads a mpls file and returns a dictionary, not a clip. There are two elements in the dictionary. The element with the key 'clip' contains a list of full path to each m2ts file in the playlist. The element with the key 'count' contains the number of m2ts file in the playlist. + + +Usage +===== + + mpls.Read(string source) + +* source: The full path of the mpls file. Don't use relative path. + +After obtaining the dictionary, you can use your favorite source filter to open them all with a for-loop and splice them together. For example: +```python +mpls = core.mpls.Read('D:/rule6/BDMV/PLAYLIST/00001.mpls') +ret = core.std.Splice([core.ffms2.Source(mpls['clip'][i]) for i in range(mpls['count'])]) +``` diff --git a/ReadMpls/ReadMpls.cpp b/ReadMpls/ReadMpls.cpp new file mode 100644 index 0000000..370bc84 --- /dev/null +++ b/ReadMpls/ReadMpls.cpp @@ -0,0 +1,47 @@ +/* + Copyright (C) 2017 HolyWu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "mpls_parse.h" +#include + +#include + +#include + +static void VS_CC readMplsCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { + const std::string source{ vsapi->propGetData(in, "source", 0, nullptr) }; + + mpls_pl * pl = bd_read_mpls(source.c_str()); + if (!pl) + return vsapi->setError(out, ("ReadMpls: failed to open " + source).c_str()); + + vsapi->propSetInt(out, "count", pl->list_count, paReplace); + for (unsigned i = 0; i < pl->list_count; i++) + vsapi->propSetData(out, "clip", (source.substr(0, source.find_last_of("/\\") - 8) + "STREAM/" + pl->play_item[i].clip[0].clip_id + ".m2ts").c_str(), -1, paAppend); + if (pl->list_count == 1) + vsapi->propSetData(out, "clip", "", -1, paAppend); + + bd_free_mpls(pl); +} + +////////////////////////////////////////// +// Init + +VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin) { + configFunc("com.holywu.readmpls", "mpls", "Reads a mpls file and returns a dict", VAPOURSYNTH_API_VERSION, 1, plugin); + registerFunc("Read", "source:data;", readMplsCreate, nullptr, plugin); +} diff --git a/ReadMpls/ReadMpls.vcxproj b/ReadMpls/ReadMpls.vcxproj new file mode 100644 index 0000000..01b8ef9 --- /dev/null +++ b/ReadMpls/ReadMpls.vcxproj @@ -0,0 +1,91 @@ + + + + + Release + Win32 + + + Release + x64 + + + + true + 15.0 + {2871074B-F3B3-42D5-BA5C-0D5532E5DCDB} + Win32Proj + ReadMpls + 10.0.15063.0 + + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + ..\libbluray32;C:\Program Files %28x86%29\VapourSynth\sdk\include\vapoursynth;$(IncludePath) + ..\libbluray32;$(LibraryPath) + + + ..\libbluray64;C:\Program Files %28x86%29\VapourSynth\sdk\include\vapoursynth;$(IncludePath) + ..\libbluray64;$(LibraryPath) + + + + NDEBUG;%(PreprocessorDefinitions) + Level3 + Column + true + true + + + Windows + true + true + libbluray.lib;%(AdditionalDependencies) + + + + + NDEBUG;%(PreprocessorDefinitions) + Level3 + Column + true + + + Windows + true + true + libbluray.lib;%(AdditionalDependencies) + + + + + + + + + \ No newline at end of file diff --git a/ReadMpls/ReadMpls.vcxproj.filters b/ReadMpls/ReadMpls.vcxproj.filters new file mode 100644 index 0000000..e1029c8 --- /dev/null +++ b/ReadMpls/ReadMpls.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/ReadMpls/mpls_parse.h b/ReadMpls/mpls_parse.h new file mode 100644 index 0000000..a06c802 --- /dev/null +++ b/ReadMpls/mpls_parse.h @@ -0,0 +1,226 @@ +/* + * This file is part of libbluray + * Copyright (C) 2009-2010 John Stebbins + * Copyright (C) 2012-2016 Petri Hintukainen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#if !defined(_MPLS_PARSE_H_) +#define _MPLS_PARSE_H_ + +#include + +#define BD_MARK_ENTRY 0x01 +#define BD_MARK_LINK 0x02 + +typedef struct bd_uo_mask_table_s +{ + unsigned int menu_call : 1; + unsigned int title_search : 1; + unsigned int chapter_search : 1; + unsigned int time_search : 1; + unsigned int skip_to_next_point : 1; + unsigned int skip_to_prev_point : 1; + unsigned int play_firstplay : 1; + unsigned int stop : 1; + unsigned int pause_on : 1; + unsigned int pause_off : 1; + unsigned int still_off : 1; + unsigned int forward : 1; + unsigned int backward : 1; + unsigned int resume : 1; + unsigned int move_up : 1; + unsigned int move_down : 1; + unsigned int move_left : 1; + unsigned int move_right : 1; + unsigned int select : 1; + unsigned int activate : 1; + unsigned int select_and_activate : 1; + unsigned int primary_audio_change : 1; + unsigned int reserved0 : 1; + unsigned int angle_change : 1; + unsigned int popup_on : 1; + unsigned int popup_off : 1; + unsigned int pg_enable_disable : 1; + unsigned int pg_change : 1; + unsigned int secondary_video_enable_disable : 1; + unsigned int secondary_video_change : 1; + unsigned int secondary_audio_enable_disable : 1; + unsigned int secondary_audio_change : 1; + unsigned int reserved1 : 1; + unsigned int pip_pg_change : 1; +} BD_UO_MASK; + +typedef struct +{ + uint8_t stream_type; + uint8_t coding_type; + uint16_t pid; + uint8_t subpath_id; + uint8_t subclip_id; + uint8_t format; + uint8_t rate; + uint8_t char_code; + char lang[4]; + // Secondary audio specific fields + uint8_t sa_num_primary_audio_ref; + uint8_t *sa_primary_audio_ref; + // Secondary video specific fields + uint8_t sv_num_secondary_audio_ref; + uint8_t sv_num_pip_pg_ref; + uint8_t *sv_secondary_audio_ref; + uint8_t *sv_pip_pg_ref; +} MPLS_STREAM; + +typedef struct +{ + uint8_t num_video; + uint8_t num_audio; + uint8_t num_pg; + uint8_t num_ig; + uint8_t num_secondary_audio; + uint8_t num_secondary_video; + uint8_t num_pip_pg; + MPLS_STREAM *video; + MPLS_STREAM *audio; + MPLS_STREAM *pg; + MPLS_STREAM *ig; + MPLS_STREAM *secondary_audio; + MPLS_STREAM *secondary_video; +} MPLS_STN; + +typedef struct +{ + char clip_id[6]; + char codec_id[5]; + uint8_t stc_id; +} MPLS_CLIP; + +typedef struct +{ + uint8_t is_multi_angle; + uint8_t connection_condition; + uint32_t in_time; + uint32_t out_time; + BD_UO_MASK uo_mask; + uint8_t random_access_flag; + uint8_t still_mode; + uint16_t still_time; + uint8_t angle_count; + uint8_t is_different_audio; + uint8_t is_seamless_angle; + MPLS_CLIP *clip; + MPLS_STN stn; +} MPLS_PI; + +typedef struct +{ + uint8_t mark_type; + uint16_t play_item_ref; + uint32_t time; + uint16_t entry_es_pid; + uint32_t duration; +} MPLS_PLM; + +typedef struct +{ + uint8_t playback_type; + uint16_t playback_count; + BD_UO_MASK uo_mask; + uint8_t random_access_flag; + uint8_t audio_mix_flag; + uint8_t lossless_bypass_flag; +} MPLS_AI; + +typedef struct +{ + uint8_t connection_condition; + uint8_t is_multi_clip; + uint32_t in_time; + uint32_t out_time; + uint16_t sync_play_item_id; + uint32_t sync_pts; + uint8_t clip_count; + MPLS_CLIP *clip; +} MPLS_SUB_PI; + +typedef struct +{ + uint8_t type; + uint8_t is_repeat; + uint8_t sub_playitem_count; + MPLS_SUB_PI *sub_play_item; +} MPLS_SUB; + +typedef enum { + pip_scaling_none = 1, /* unscaled */ + pip_scaling_half = 2, /* 1:2 */ + pip_scaling_quarter = 3, /* 1:4 */ + pip_scaling_one_half = 4, /* 3:2 */ + pip_scaling_fullscreen = 5, /* scale to main video size */ +} mpls_pip_scaling; + +typedef struct { + uint32_t time; /* start timestamp (clip time) when the block is valid */ + uint16_t xpos; + uint16_t ypos; + uint8_t scale_factor; /* mpls_pip_scaling. Note: PSR14 may override this ! */ +} MPLS_PIP_DATA; + +typedef enum { + pip_timeline_sync_mainpath = 1, /* timeline refers to main path */ + pip_timeline_async_subpath = 2, /* timeline refers to sub-path time */ + pip_timeline_async_mainpath = 3, /* timeline refers to main path */ +} mpls_pip_timeline; + +typedef struct { + uint16_t clip_ref; /* clip id for secondary_video_ref (STN) */ + uint8_t secondary_video_ref; /* secondary video stream id (STN) */ + uint8_t timeline_type; /* mpls_pip_timeline */ + uint8_t luma_key_flag; /* use luma keying */ + uint8_t upper_limit_luma_key; /* luma key (secondary video pixels with Y <= this value are transparent) */ + uint8_t trick_play_flag; /* show synchronous PiP when playing trick speed */ + + uint16_t data_count; + MPLS_PIP_DATA *data; +} MPLS_PIP_METADATA; + +typedef struct mpls_pl +{ + uint32_t type_indicator; + uint32_t type_indicator2; + uint32_t list_pos; + uint32_t mark_pos; + uint32_t ext_pos; + MPLS_AI app_info; + uint16_t list_count; + uint16_t sub_count; + uint16_t mark_count; + MPLS_PI *play_item; + MPLS_SUB *sub_path; + MPLS_PLM *play_mark; + + // extension data (profile 5, version 2.4) + uint16_t ext_sub_count; + MPLS_SUB *ext_sub_path; // sub path entries extension + + // extension data (Picture-In-Picture metadata) + uint16_t ext_pip_data_count; + MPLS_PIP_METADATA *ext_pip_data; // pip metadata extension + +} MPLS_PL; + +#endif // _MPLS_PARSE_H_