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_