From 27f00a8a0c339b0dd1fcbef3c4309a0a9d4212b4 Mon Sep 17 00:00:00 2001 From: "yuzhuohuang@qq.com" Date: Fri, 16 Dec 2011 08:43:59 +0800 Subject: [PATCH] Merge some MPC-HC Rev.3895 code to get HdmvSub and DVBSub support. --- src/dsutil/DSUtil.cpp | 411 ++++++++++++------ src/dsutil/DSUtil.h | 37 ++ src/dsutil/GolombBuffer.cpp | 117 +++++ src/dsutil/GolombBuffer.h | 74 ++++ src/dsutil/H264Nalu.cpp | 108 +++++ src/dsutil/H264Nalu.h | 94 +++++ src/dsutil/HdmvClipInfo.cpp | 468 ++++++++++++++++++++ src/dsutil/HdmvClipInfo.h | 172 ++++++++ src/dsutil/Mpeg2Def.h | 157 +++++++ src/dsutil/dsutil_vs2010.vcxproj | 7 + src/dsutil/dsutil_vs2010.vcxproj.filters | 21 + src/subtitles/BaseSub.cpp | 33 ++ src/subtitles/BaseSub.h | 53 +++ src/subtitles/CompositionObject.cpp | 354 ++++++++++++++++ src/subtitles/CompositionObject.h | 93 ++++ src/subtitles/DVBSub.cpp | 564 +++++++++++++++++++++++++ src/subtitles/DVBSub.h | 214 ++++++++++ src/subtitles/GFN.cpp | 6 +- src/subtitles/GFN.h | 2 +- src/subtitles/HdmvSub.cpp | 375 ++++++++++++++++ src/subtitles/HdmvSub.h | 121 ++++++ src/subtitles/Rasterizer.cpp | 23 +- src/subtitles/Rasterizer.h | 5 +- src/subtitles/RenderedHdmvSubtitle.cpp | 179 ++++++++ src/subtitles/RenderedHdmvSubtitle.h | 71 ++++ src/subtitles/STS.h | 1 + src/subtitles/SubtitleInputPin.cpp | 60 ++- src/subtitles/SubtitleInputPin.h | 1 + src/subtitles/subtitles_vs2010.vcxproj | 10 + src/subtitles/subtitles_vs2010.vcxproj.filters | 30 ++ 30 files changed, 3714 insertions(+), 147 deletions(-) create mode 100644 src/dsutil/GolombBuffer.cpp create mode 100644 src/dsutil/GolombBuffer.h create mode 100644 src/dsutil/H264Nalu.cpp create mode 100644 src/dsutil/H264Nalu.h create mode 100644 src/dsutil/HdmvClipInfo.cpp create mode 100644 src/dsutil/HdmvClipInfo.h create mode 100644 src/dsutil/Mpeg2Def.h create mode 100644 src/subtitles/BaseSub.cpp create mode 100644 src/subtitles/BaseSub.h create mode 100644 src/subtitles/CompositionObject.cpp create mode 100644 src/subtitles/CompositionObject.h create mode 100644 src/subtitles/DVBSub.cpp create mode 100644 src/subtitles/DVBSub.h create mode 100644 src/subtitles/HdmvSub.cpp create mode 100644 src/subtitles/HdmvSub.h create mode 100644 src/subtitles/RenderedHdmvSubtitle.cpp create mode 100644 src/subtitles/RenderedHdmvSubtitle.h diff --git a/src/dsutil/DSUtil.cpp b/src/dsutil/DSUtil.cpp index b2107b1..2f1d863 100644 --- a/src/dsutil/DSUtil.cpp +++ b/src/dsutil/DSUtil.cpp @@ -24,8 +24,15 @@ #include "..\..\include\winddk\devioctl.h" #include "..\..\include\winddk\ntddcdrm.h" #include "DSUtil.h" -#include "..\..\include\moreuuids.h" +#include "Mpeg2Def.h" +#include "vd.h" +#include "..\..\..\include\moreuuids.h" #include +#include +#include +#include +#include +#include void DumpStreamConfig(TCHAR* fn, IAMStreamConfig* pAMVSCCap) { @@ -1480,35 +1487,37 @@ CStringA UTF16To8(LPCWSTR utf16) return str; } -static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = -{ +static struct { + LPCSTR name, iso6392, iso6391; + LCID lcid; +} s_isolangs[] = { // TODO : fill LCID !!! {"Abkhazian", "abk", "ab"}, {"Achinese", "ace", ""}, {"Acoli", "ach", ""}, {"Adangme", "ada", ""}, {"Afar", "aar", "aa"}, {"Afrihili", "afh", ""}, - {"Afrikaans", "afr", "af"}, + {"Afrikaans", "afr", "af", MAKELCID( MAKELANGID(LANG_AFRIKAANS, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Afro-Asiatic (Other)", "afa", ""}, {"Akan", "aka", "ak"}, {"Akkadian", "akk", ""}, {"Albanian", "alb", "sq"}, - {"Albanian", "sqi", "sq"}, + {"Albanian", "sqi", "sq", MAKELCID( MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Aleut", "ale", ""}, {"Algonquian languages", "alg", ""}, {"Altaic (Other)", "tut", ""}, {"Amharic", "amh", "am"}, {"Apache languages", "apa", ""}, - {"Arabic", "ara", "ar"}, + {"Arabic", "ara", "ar", MAKELCID( MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Aragonese", "arg", "an"}, {"Aramaic", "arc", ""}, {"Arapaho", "arp", ""}, {"Araucanian", "arn", ""}, {"Arawak", "arw", ""}, - {"Armenian", "arm", "hy"}, - {"Armenian", "hye", "hy"}, + {"Armenian", "arm", "hy", MAKELCID( MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Armenian", "hye", "hy", MAKELCID( MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Artificial (Other)", "art", ""}, - {"Assamese", "asm", "as"}, + {"Assamese", "asm", "as", MAKELCID( MAKELANGID(LANG_ASSAMESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Asturian; Bable", "ast", ""}, {"Athapascan languages", "ath", ""}, {"Australian languages", "aus", ""}, @@ -1517,7 +1526,7 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Avestan", "ave", "ae"}, {"Awadhi", "awa", ""}, {"Aymara", "aym", "ay"}, - {"Azerbaijani", "aze", "az"}, + {"Azerbaijani", "aze", "az", MAKELCID( MAKELANGID(LANG_AZERI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Bable; Asturian", "ast", ""}, {"Balinese", "ban", ""}, {"Baltic (Other)", "bat", ""}, @@ -1527,14 +1536,14 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Banda", "bad", ""}, {"Bantu (Other)", "bnt", ""}, {"Basa", "bas", ""}, - {"Bashkir", "bak", "ba"}, - {"Basque", "baq", "eu"}, - {"Basque", "eus", "eu"}, + {"Bashkir", "bak", "ba", MAKELCID( MAKELANGID(LANG_BASHKIR, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Basque", "baq", "eu", MAKELCID( MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Basque", "eus", "eu", MAKELCID( MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Batak (Indonesia)", "btk", ""}, {"Beja", "bej", ""}, - {"Belarusian", "bel", "be"}, + {"Belarusian", "bel", "be", MAKELCID( MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Bemba", "bem", ""}, - {"Bengali", "ben", "bn"}, + {"Bengali", "ben", "bn", MAKELCID( MAKELANGID(LANG_BENGALI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Berber (Other)", "ber", ""}, {"Bhojpuri", "bho", ""}, {"Bihari", "bih", "bh"}, @@ -1544,16 +1553,16 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Bokmål, Norwegian; Norwegian Bokmål", "nob", "nb"}, {"Bosnian", "bos", "bs"}, {"Braj", "bra", ""}, - {"Breton", "bre", "br"}, + {"Breton", "bre", "br", MAKELCID( MAKELANGID(LANG_BRETON, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Buginese", "bug", ""}, - {"Bulgarian", "bul", "bg"}, + {"Bulgarian", "bul", "bg", MAKELCID( MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Buriat", "bua", ""}, {"Burmese", "bur", "my"}, {"Burmese", "mya", "my"}, {"Caddo", "cad", ""}, {"Carib", "car", ""}, - {"Spanish; Castilian", "spa", "es"}, - {"Catalan", "cat", "ca"}, + {"Spanish; Castilian", "spa", "es", MAKELCID( MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Catalan", "cat", "ca", MAKELCID( MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Caucasian (Other)", "cau", ""}, {"Cebuano", "ceb", ""}, {"Celtic (Other)", "cel", ""}, @@ -1567,7 +1576,7 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Cheyenne", "chy", ""}, {"Chibcha", "chb", ""}, {"Chichewa; Chewa; Nyanja", "nya", "ny"}, - {"Chinese", "chi", "zh"}, + {"Chinese", "chi", "zh", MAKELCID( MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Chinese", "zho", "zh"}, {"Chinook jargon", "chn", ""}, {"Chipewyan", "chp", ""}, @@ -1582,7 +1591,7 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Chuvash", "chv", "cv"}, {"Coptic", "cop", ""}, {"Cornish", "cor", "kw"}, - {"Corsican", "cos", "co"}, + {"Corsican", "cos", "co", MAKELCID( MAKELANGID(LANG_CORSICAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Cree", "cre", "cr"}, {"Creek", "mus", ""}, {"Creoles and pidgins (Other)", "crp", ""}, @@ -1592,24 +1601,24 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = // {"French-based (Other)", "", ""}, {"Creoles and pidgins,", "cpp", ""}, // {"Portuguese-based (Other)", "", ""}, - {"Croatian", "scr", "hr"}, - {"Croatian", "hrv", "hr"}, + {"Croatian", "scr", "hr", MAKELCID( MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Croatian", "hrv", "hr", MAKELCID( MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Cushitic (Other)", "cus", ""}, - {"Czech", "cze", "cs"}, - {"Czech", "ces", "cs"}, + {"Czech", "cze", "cs", MAKELCID( MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Czech", "ces", "cs", MAKELCID( MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Dakota", "dak", ""}, - {"Danish", "dan", "da"}, + {"Danish", "dan", "da", MAKELCID( MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Dargwa", "dar", ""}, {"Dayak", "day", ""}, {"Delaware", "del", ""}, {"Dinka", "din", ""}, - {"Divehi", "div", "dv"}, + {"Divehi", "div", "dv", MAKELCID( MAKELANGID(LANG_DIVEHI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Dogri", "doi", ""}, {"Dogrib", "dgr", ""}, {"Dravidian (Other)", "dra", ""}, {"Duala", "dua", ""}, - {"Dutch; Flemish", "dut", "nl"}, - {"Dutch; Flemish", "nld", "nl"}, + {"Dutch; Flemish", "dut", "nl", MAKELCID( MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Dutch; Flemish", "nld", "nl", MAKELCID( MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Dutch, Middle (ca. 1050-1350)", "dum", ""}, {"Dyula", "dyu", ""}, {"Dzongkha", "dzo", "dz"}, @@ -1617,40 +1626,41 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Egyptian (Ancient)", "egy", ""}, {"Ekajuk", "eka", ""}, {"Elamite", "elx", ""}, - {"English", "eng", "en"}, + {"English", "eng", "en", MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"English, Middle (1100-1500)", "enm", ""}, {"English, Old (ca.450-1100)", "ang", ""}, {"Esperanto", "epo", "eo"}, - {"Estonian", "est", "et"}, + {"Estonian", "est", "et", MAKELCID( MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Ewe", "ewe", "ee"}, {"Ewondo", "ewo", ""}, {"Fang", "fan", ""}, {"Fanti", "fat", ""}, - {"Faroese", "fao", "fo"}, + {"Faroese", "fao", "fo", MAKELCID( MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Fijian", "fij", "fj"}, - {"Finnish", "fin", "fi"}, + {"Finnish", "fin", "fi", MAKELCID( MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Finno-Ugrian (Other)", "fiu", ""}, {"Flemish; Dutch", "dut", "nl"}, {"Flemish; Dutch", "nld", "nl"}, {"Fon", "fon", ""}, - {"French", "fre", "fr"}, - {"French", "fra*", "fr"}, + {"French", "fre", "fr", MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"French", "fra*", "fr", MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"French", "fra", "fr", MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"French, Middle (ca.1400-1600)", "frm", ""}, {"French, Old (842-ca.1400)", "fro", ""}, - {"Frisian", "fry", "fy"}, + {"Frisian", "fry", "fy", MAKELCID( MAKELANGID(LANG_FRISIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Friulian", "fur", ""}, {"Fulah", "ful", "ff"}, {"Ga", "gaa", ""}, - {"Gaelic; Scottish Gaelic", "gla", "gd"}, + {"Gaelic; Scottish Gaelic", "gla", "gd", MAKELCID( MAKELANGID(LANG_GALICIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Gallegan", "glg", "gl"}, {"Ganda", "lug", "lg"}, {"Gayo", "gay", ""}, {"Gbaya", "gba", ""}, {"Geez", "gez", ""}, - {"Georgian", "geo", "ka"}, - {"Georgian", "kat", "ka"}, - {"German", "ger", "de"}, - {"German", "deu", "de"}, + {"Georgian", "geo", "ka", MAKELCID( MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Georgian", "kat", "ka", MAKELCID( MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"German", "ger", "de", MAKELCID( MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"German", "deu", "de", MAKELCID( MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"German, Low; Saxon, Low; Low German; Low Saxon", "nds", ""}, {"German, Middle High (ca.1050-1500)", "gmh", ""}, {"German, Old High (ca.750-1050)", "goh", ""}, @@ -1661,50 +1671,50 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Gorontalo", "gor", ""}, {"Gothic", "got", ""}, {"Grebo", "grb", ""}, - {"Greek, Ancient (to 1453)", "grc", ""}, - {"Greek, Modern (1453-)", "gre", "el"}, - {"Greek, Modern (1453-)", "ell", "el"}, - {"Greenlandic; Kalaallisut", "kal", "kl"}, + {"Greek, Ancient (to 1453)", "grc", "", MAKELCID( MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Greek, Modern (1453-)", "gre", "el", MAKELCID( MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Greek, Modern (1453-)", "ell", "el", MAKELCID( MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Greenlandic; Kalaallisut", "kal", "kl", MAKELCID( MAKELANGID(LANG_GREENLANDIC, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Guarani", "grn", "gn"}, - {"Gujarati", "guj", "gu"}, + {"Gujarati", "guj", "gu", MAKELCID( MAKELANGID(LANG_GUJARATI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Gwich´in", "gwi", ""}, {"Haida", "hai", ""}, - {"Hausa", "hau", "ha"}, + {"Hausa", "hau", "ha", MAKELCID( MAKELANGID(LANG_HAUSA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Hawaiian", "haw", ""}, - {"Hebrew", "heb", "he"}, + {"Hebrew", "heb", "he", MAKELCID( MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Herero", "her", "hz"}, {"Hiligaynon", "hil", ""}, {"Himachali", "him", ""}, - {"Hindi", "hin", "hi"}, + {"Hindi", "hin", "hi", MAKELCID( MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Hiri Motu", "hmo", "ho"}, {"Hittite", "hit", ""}, {"Hmong", "hmn", ""}, - {"Hungarian", "hun", "hu"}, + {"Hungarian", "hun", "hu", MAKELCID( MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Hupa", "hup", ""}, {"Iban", "iba", ""}, - {"Icelandic", "ice", "is"}, - {"Icelandic", "isl", "is"}, + {"Icelandic", "ice", "is", MAKELCID( MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Icelandic", "isl", "is", MAKELCID( MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Ido", "ido", "io"}, - {"Igbo", "ibo", "ig"}, + {"Igbo", "ibo", "ig", MAKELCID( MAKELANGID(LANG_IGBO, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Ijo", "ijo", ""}, {"Iloko", "ilo", ""}, {"Inari Sami", "smn", ""}, {"Indic (Other)", "inc", ""}, {"Indo-European (Other)", "ine", ""}, - {"Indonesian", "ind", "id"}, + {"Indonesian", "ind", "id", MAKELCID( MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Ingush", "inh", ""}, {"Interlingua (International", "ina", "ia"}, // {"Auxiliary Language Association)", "", ""}, {"Interlingue", "ile", "ie"}, - {"Inuktitut", "iku", "iu"}, + {"Inuktitut", "iku", "iu", MAKELCID( MAKELANGID(LANG_INUKTITUT, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Inupiaq", "ipk", "ik"}, {"Iranian (Other)", "ira", ""}, - {"Irish", "gle", "ga"}, - {"Irish, Middle (900-1200)", "mga", ""}, - {"Irish, Old (to 900)", "sga", ""}, + {"Irish", "gle", "ga", MAKELCID( MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Irish, Middle (900-1200)", "mga", "", MAKELCID( MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Irish, Old (to 900)", "sga", "", MAKELCID( MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Iroquoian languages", "iro", ""}, - {"Italian", "ita", "it"}, - {"Japanese", "jpn", "ja"}, + {"Italian", "ita", "it", MAKELCID( MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Japanese", "jpn", "ja", MAKELCID( MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Javanese", "jav", "jv"}, {"Judeo-Arabic", "jrb", ""}, {"Judeo-Persian", "jpr", ""}, @@ -1713,25 +1723,25 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Kachin", "kac", ""}, {"Kalaallisut; Greenlandic", "kal", "kl"}, {"Kamba", "kam", ""}, - {"Kannada", "kan", "kn"}, + {"Kannada", "kan", "kn", MAKELCID( MAKELANGID(LANG_KANNADA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Kanuri", "kau", "kr"}, {"Kara-Kalpak", "kaa", ""}, {"Karen", "kar", ""}, - {"Kashmiri", "kas", "ks"}, + {"Kashmiri", "kas", "ks", MAKELCID( MAKELANGID(LANG_KASHMIRI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Kawi", "kaw", ""}, - {"Kazakh", "kaz", "kk"}, + {"Kazakh", "kaz", "kk", MAKELCID( MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Khasi", "kha", ""}, - {"Khmer", "khm", "km"}, + {"Khmer", "khm", "km", MAKELCID( MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Khoisan (Other)", "khi", ""}, {"Khotanese", "kho", ""}, {"Kikuyu; Gikuyu", "kik", "ki"}, {"Kimbundu", "kmb", ""}, - {"Kinyarwanda", "kin", "rw"}, + {"Kinyarwanda", "kin", "rw", MAKELCID( MAKELANGID(LANG_KINYARWANDA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Kirghiz", "kir", "ky"}, {"Komi", "kom", "kv"}, {"Kongo", "kon", "kg"}, - {"Konkani", "kok", ""}, - {"Korean", "kor", "ko"}, + {"Konkani", "kok", "", MAKELCID( MAKELANGID(LANG_KONKANI, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Korean", "kor", "ko", MAKELCID( MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Kosraean", "kos", ""}, {"Kpelle", "kpe", ""}, {"Kru", "kro", ""}, @@ -1744,16 +1754,16 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Ladino", "lad", ""}, {"Lahnda", "lah", ""}, {"Lamba", "lam", ""}, - {"Lao", "lao", "lo"}, + {"Lao", "lao", "lo", MAKELCID( MAKELANGID(LANG_LAO, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Latin", "lat", "la"}, - {"Latvian", "lav", "lv"}, + {"Latvian", "lav", "lv", MAKELCID( MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Letzeburgesch; Luxembourgish", "ltz", "lb"}, {"Lezghian", "lez", ""}, {"Limburgan; Limburger; Limburgish", "lim", "li"}, {"Limburger; Limburgan; Limburgish;", "lim", "li"}, {"Limburgish; Limburger; Limburgan", "lim", "li"}, {"Lingala", "lin", "ln"}, - {"Lithuanian", "lit", "lt"}, + {"Lithuanian", "lit", "lt", MAKELCID( MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Low German; Low Saxon; German, Low; Saxon, Low", "nds", ""}, {"Low Saxon; Low German; Saxon, Low; German, Low", "nds", ""}, {"Lozi", "loz", ""}, @@ -1764,27 +1774,27 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Lunda", "lun", ""}, {"Luo (Kenya and Tanzania)", "luo", ""}, {"Lushai", "lus", ""}, - {"Luxembourgish; Letzeburgesch", "ltz", "lb"}, - {"Macedonian", "mac", "mk"}, - {"Macedonian", "mkd", "mk"}, + {"Luxembourgish; Letzeburgesch", "ltz", "lb", MAKELCID( MAKELANGID(LANG_LUXEMBOURGISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Macedonian", "mac", "mk", MAKELCID( MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Macedonian", "mkd", "mk", MAKELCID( MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Madurese", "mad", ""}, {"Magahi", "mag", ""}, {"Maithili", "mai", ""}, {"Makasar", "mak", ""}, {"Malagasy", "mlg", "mg"}, - {"Malay", "may", "ms"}, - {"Malay", "msa", "ms"}, - {"Malayalam", "mal", "ml"}, - {"Maltese", "mlt", "mt"}, + {"Malay", "may", "ms", MAKELCID( MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Malay", "msa", "ms", MAKELCID( MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Malayalam", "mal", "ml", MAKELCID( MAKELANGID(LANG_MALAYALAM, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Maltese", "mlt", "mt", MAKELCID( MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Manchu", "mnc", ""}, {"Mandar", "mdr", ""}, {"Mandingo", "man", ""}, - {"Manipuri", "mni", ""}, + {"Manipuri", "mni", "", MAKELCID( MAKELANGID(LANG_MANIPURI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Manobo languages", "mno", ""}, {"Manx", "glv", "gv"}, - {"Maori", "mao", "mi"}, - {"Maori", "mri", "mi"}, - {"Marathi", "mar", "mr"}, + {"Maori", "mao", "mi", MAKELCID( MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Maori", "mri", "mi", MAKELCID( MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Marathi", "mar", "mr", MAKELCID( MAKELANGID(LANG_MARATHI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Mari", "chm", ""}, {"Marshallese", "mah", "mh"}, {"Marwari", "mwr", ""}, @@ -1794,11 +1804,11 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Micmac", "mic", ""}, {"Minangkabau", "min", ""}, {"Miscellaneous languages", "mis", ""}, - {"Mohawk", "moh", ""}, + {"Mohawk", "moh", "", MAKELCID( MAKELANGID(LANG_MOHAWK, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Moldavian", "mol", "mo"}, {"Mon-Khmer (Other)", "mkh", ""}, {"Mongo", "lol", ""}, - {"Mongolian", "mon", "mn"}, + {"Mongolian", "mon", "mn", MAKELCID( MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Mossi", "mos", ""}, {"Multiple languages", "mul", ""}, {"Munda languages", "mun", ""}, @@ -1810,7 +1820,7 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Ndebele, South", "nbl", "nr"}, {"Ndonga", "ndo", "ng"}, {"Neapolitan", "nap", ""}, - {"Nepali", "nep", "ne"}, + {"Nepali", "nep", "ne", MAKELCID( MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Newari", "new", ""}, {"Nias", "nia", ""}, {"Niger-Kordofanian (Other)", "nic", ""}, @@ -1820,9 +1830,9 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"North American Indian (Other)", "nai", ""}, {"Northern Sami", "sme", "se"}, {"North Ndebele", "nde", "nd"}, - {"Norwegian", "nor", "no"}, - {"Norwegian Bokmål; Bokmål, Norwegian", "nob", "nb"}, - {"Norwegian Nynorsk; Nynorsk, Norwegian", "nno", "nn"}, + {"Norwegian", "nor", "no", MAKELCID( MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Norwegian Bokmål; Bokmål, Norwegian", "nob", "nb", MAKELCID( MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Norwegian Nynorsk; Nynorsk, Norwegian", "nno", "nn", MAKELCID( MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Nubian languages", "nub", ""}, {"Nyamwezi", "nym", ""}, {"Nyanja; Chichewa; Chewa", "nya", "ny"}, @@ -1830,7 +1840,7 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Nynorsk, Norwegian; Norwegian Nynorsk", "nno", "nn"}, {"Nyoro", "nyo", ""}, {"Nzima", "nzi", ""}, - {"Occitan (post 1500},; Provençal", "oci", "oc"}, + {"Occitan (post 1500},; Provençal", "oci", "oc", MAKELCID( MAKELANGID(LANG_OCCITAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Ojibwa", "oji", "oj"}, {"Old Bulgarian; Old Slavonic; Church Slavonic;", "chu", "cu"}, {"Oriya", "ori", "or"}, @@ -1847,37 +1857,37 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Panjabi", "pan", "pa"}, {"Papiamento", "pap", ""}, {"Papuan (Other)", "paa", ""}, - {"Persian", "per", "fa"}, - {"Persian", "fas", "fa"}, + {"Persian", "per", "fa", MAKELCID( MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Persian", "fas", "fa", MAKELCID( MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Persian, Old (ca.600-400 B.C.)", "peo", ""}, {"Philippine (Other)", "phi", ""}, {"Phoenician", "phn", ""}, {"Pohnpeian", "pon", ""}, - {"Polish", "pol", "pl"}, - {"Portuguese", "por", "pt"}, + {"Polish", "pol", "pl", MAKELCID( MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Portuguese", "por", "pt", MAKELCID( MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Prakrit languages", "pra", ""}, {"Provençal; Occitan (post 1500)", "oci", "oc"}, {"Provençal, Old (to 1500)", "pro", ""}, {"Pushto", "pus", "ps"}, - {"Quechua", "que", "qu"}, + {"Quechua", "que", "qu", MAKELCID( MAKELANGID(LANG_QUECHUA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Raeto-Romance", "roh", "rm"}, {"Rajasthani", "raj", ""}, {"Rapanui", "rap", ""}, {"Rarotongan", "rar", ""}, {"Reserved for local use", "qaa-qtz", ""}, {"Romance (Other)", "roa", ""}, - {"Romanian", "rum", "ro"}, - {"Romanian", "ron", "ro"}, + {"Romanian", "rum", "ro", MAKELCID( MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Romanian", "ron", "ro", MAKELCID( MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Romany", "rom", ""}, {"Rundi", "run", "rn"}, - {"Russian", "rus", "ru"}, + {"Russian", "rus", "ru", MAKELCID( MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Salishan languages", "sal", ""}, {"Samaritan Aramaic", "sam", ""}, {"Sami languages (Other)", "smi", ""}, {"Samoan", "smo", "sm"}, {"Sandawe", "sad", ""}, {"Sango", "sag", "sg"}, - {"Sanskrit", "san", "sa"}, + {"Sanskrit", "san", "sa", MAKELCID( MAKELANGID(LANG_SANSKRIT, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Santali", "sat", ""}, {"Sardinian", "srd", "sc"}, {"Sasak", "sas", ""}, @@ -1886,8 +1896,8 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Scottish Gaelic; Gaelic", "gla", "gd"}, {"Selkup", "sel", ""}, {"Semitic (Other)", "sem", ""}, - {"Serbian", "scc", "sr"}, - {"Serbian", "srp", "sr"}, + {"Serbian", "scc", "sr", MAKELCID( MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Serbian", "srp", "sr", MAKELCID( MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Serer", "srr", ""}, {"Shan", "shn", ""}, {"Shona", "sna", "sn"}, @@ -1895,50 +1905,50 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Sidamo", "sid", ""}, {"Sign languages", "sgn", ""}, {"Siksika", "bla", ""}, - {"Sindhi", "snd", "sd"}, - {"Sinhalese", "sin", "si"}, + {"Sindhi", "snd", "sd", MAKELCID( MAKELANGID(LANG_SINDHI, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Sinhalese", "sin", "si", MAKELCID( MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Sino-Tibetan (Other)", "sit", ""}, {"Siouan languages", "sio", ""}, {"Skolt Sami", "sms", ""}, {"Slave (Athapascan)", "den", ""}, {"Slavic (Other)", "sla", ""}, - {"Slovak", "slo", "sk"}, - {"Slovak", "slk", "sk"}, - {"Slovenian", "slv", "sl"}, + {"Slovak", "slo", "sk", MAKELCID( MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Slovak", "slk", "sk", MAKELCID( MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Slovenian", "slv", "sl", MAKELCID( MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Sogdian", "sog", ""}, {"Somali", "som", "so"}, {"Songhai", "son", ""}, {"Soninke", "snk", ""}, {"Sorbian languages", "wen", ""}, - {"Sotho, Northern", "nso", ""}, - {"Sotho, Southern", "sot", "st"}, + {"Sotho, Northern", "nso", "", MAKELCID( MAKELANGID(LANG_SOTHO, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Sotho, Southern", "sot", "st", MAKELCID( MAKELANGID(LANG_SOTHO, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"South American Indian (Other)", "sai", ""}, {"Southern Sami", "sma", ""}, {"South Ndebele", "nbl", "nr"}, - {"Spanish; Castilian", "spa", "es"}, + {"Spanish; Castilian", "spa", "es", MAKELCID( MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Sukuma", "suk", ""}, {"Sumerian", "sux", ""}, {"Sundanese", "sun", "su"}, {"Susu", "sus", ""}, - {"Swahili", "swa", "sw"}, + {"Swahili", "swa", "sw", MAKELCID( MAKELANGID(LANG_SWAHILI, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Swati", "ssw", "ss"}, - {"Swedish", "swe", "sv"}, - {"Syriac", "syr", ""}, + {"Swedish", "swe", "sv", MAKELCID( MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Syriac", "syr", "", MAKELCID( MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Tagalog", "tgl", "tl"}, {"Tahitian", "tah", "ty"}, {"Tai (Other)", "tai", ""}, - {"Tajik", "tgk", "tg"}, + {"Tajik", "tgk", "tg", MAKELCID( MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Tamashek", "tmh", ""}, - {"Tamil", "tam", "ta"}, - {"Tatar", "tat", "tt"}, - {"Telugu", "tel", "te"}, + {"Tamil", "tam", "ta", MAKELCID( MAKELANGID(LANG_TAMIL, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Tatar", "tat", "tt", MAKELCID( MAKELANGID(LANG_TATAR, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Telugu", "tel", "te", MAKELCID( MAKELANGID(LANG_TELUGU, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Tereno", "ter", ""}, {"Tetum", "tet", ""}, - {"Thai", "tha", "th"}, - {"Tibetan", "tib", "bo"}, - {"Tibetan", "bod", "bo"}, + {"Thai", "tha", "th", MAKELCID( MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Tibetan", "tib", "bo", MAKELCID( MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Tibetan", "bod", "bo", MAKELCID( MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Tigre", "tig", ""}, - {"Tigrinya", "tir", "ti"}, + {"Tigrinya", "tir", "ti", MAKELCID( MAKELANGID(LANG_TIGRIGNA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Timne", "tem", ""}, {"Tiv", "tiv", ""}, {"Tlingit", "tli", ""}, @@ -1948,47 +1958,47 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Tonga (Tonga Islands)", "ton", "to"}, {"Tsimshian", "tsi", ""}, {"Tsonga", "tso", "ts"}, - {"Tswana", "tsn", "tn"}, + {"Tswana", "tsn", "tn", MAKELCID( MAKELANGID(LANG_TSWANA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Tumbuka", "tum", ""}, {"Tupi languages", "tup", ""}, - {"Turkish", "tur", "tr"}, - {"Turkish, Ottoman (1500-1928)", "ota", ""}, - {"Turkmen", "tuk", "tk"}, + {"Turkish", "tur", "tr", MAKELCID( MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Turkish, Ottoman (1500-1928)", "ota", "", MAKELCID( MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Turkmen", "tuk", "tk", MAKELCID( MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Tuvalu", "tvl", ""}, {"Tuvinian", "tyv", ""}, {"Twi", "twi", "tw"}, {"Ugaritic", "uga", ""}, - {"Uighur", "uig", "ug"}, - {"Ukrainian", "ukr", "uk"}, + {"Uighur", "uig", "ug", MAKELCID( MAKELANGID(LANG_UIGHUR, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Ukrainian", "ukr", "uk", MAKELCID( MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Umbundu", "umb", ""}, {"Undetermined", "und", ""}, - {"Urdu", "urd", "ur"}, - {"Uzbek", "uzb", "uz"}, + {"Urdu", "urd", "ur", MAKELCID( MAKELANGID(LANG_URDU, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Uzbek", "uzb", "uz", MAKELCID( MAKELANGID(LANG_UZBEK, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Vai", "vai", ""}, {"Venda", "ven", "ve"}, - {"Vietnamese", "vie", "vi"}, - {"Volapük", "vol", "vo"}, + {"Vietnamese", "vie", "vi", MAKELCID( MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Volapuk", "vol", "vo"}, {"Votic", "vot", ""}, {"Wakashan languages", "wak", ""}, {"Walamo", "wal", ""}, {"Walloon", "wln", "wa"}, {"Waray", "war", ""}, {"Washo", "was", ""}, - {"Welsh", "wel", "cy"}, - {"Welsh", "cym", "cy"}, - {"Wolof", "wol", "wo"}, - {"Xhosa", "xho", "xh"}, - {"Yakut", "sah", ""}, + {"Welsh", "wel", "cy", MAKELCID( MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Welsh", "cym", "cy", MAKELCID( MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Wolof", "wol", "wo", MAKELCID( MAKELANGID(LANG_WOLOF, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Xhosa", "xho", "xh", MAKELCID( MAKELANGID(LANG_XHOSA, SUBLANG_DEFAULT), SORT_DEFAULT)}, + {"Yakut", "sah", "", MAKELCID( MAKELANGID(LANG_YAKUT, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Yao", "yao", ""}, {"Yapese", "yap", ""}, {"Yiddish", "yid", "yi"}, - {"Yoruba", "yor", "yo"}, + {"Yoruba", "yor", "yo", MAKELCID( MAKELANGID(LANG_YORUBA, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Yupik languages", "ypk", ""}, {"Zande", "znd", ""}, {"Zapotec", "zap", ""}, {"Zenaga", "zen", ""}, {"Zhuang; Chuang", "zha", "za"}, - {"Zulu", "zul", "zu"}, + {"Zulu", "zul", "zu", MAKELCID( MAKELANGID(LANG_ZULU, SUBLANG_DEFAULT), SORT_DEFAULT)}, {"Zuni", "zun", ""}, {"Classical Newari", "nwc", ""}, {"Klingon", "tlh", ""}, @@ -2009,6 +2019,7 @@ static struct {LPCSTR name, iso6392, iso6391;} s_isolangs[] = {"Haitian", "hat", "ht"}, {"Kalmyk", "xal", ""}, {"", "", ""}, + {"No subtitles", "---", "", (LCID)LCID_NOSUBTITLES}, }; CString ISO6391ToLanguage(LPCSTR code) @@ -2044,7 +2055,35 @@ CString ISO6392ToLanguage(LPCSTR code) return ret; } } - return _T(""); + return CString(code); +} + +LCID ISO6391ToLcid(LPCSTR code) +{ + CHAR tmp[3+1]; + strncpy_s(tmp, code, 3); + tmp[3] = 0; + _strlwr_s(tmp); + for(ptrdiff_t i = 0, j = countof(s_isolangs); i < j; i++) { + if(!strcmp(s_isolangs[i].iso6391, code)) { + return s_isolangs[i].lcid; + } + } + return 0; +} + +LCID ISO6392ToLcid(LPCSTR code) +{ + CHAR tmp[3+1]; + strncpy_s(tmp, code, 3); + tmp[3] = 0; + _strlwr_s(tmp); + for(ptrdiff_t i = 0, j = countof(s_isolangs); i < j; i++) { + if(!strcmp(s_isolangs[i].iso6392, tmp)) { + return s_isolangs[i].lcid; + } + } + return 0; } CString ISO6391To6392(LPCSTR code) @@ -2254,3 +2293,103 @@ void UnRegisterSourceFilter(const GUID& subtype) { DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype)); } + +// hour, minute, second, millisec +CString ReftimeToString(const REFERENCE_TIME& rtVal) +{ + CString strTemp; + LONGLONG llTotalMs = ConvertToMilliseconds (rtVal); + int lHour = (int)(llTotalMs / (1000*60*60)); + int lMinute = (llTotalMs / (1000*60)) % 60; + int lSecond = (llTotalMs / 1000) % 60; + int lMillisec = llTotalMs % 1000; + strTemp.Format (_T("%02d:%02d:%02d,%03d"), lHour, lMinute, lSecond, lMillisec); + return strTemp; +} + +// hour, minute, second (round) +CString ReftimeToString2(const REFERENCE_TIME& rtVal) +{ + CString strTemp; + LONGLONG seconds = (rtVal + 5000000) / 10000000; + int lHour = (int)(seconds / 3600); + int lMinute = (int)(seconds / 60 % 60); + int lSecond = (int)(seconds % 60); + + strTemp.Format (_T("%02d:%02d:%02d"), lHour, lMinute, lSecond); + return strTemp; +} + +CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours) +{ + CString strTemp; + if (rtVal.bHours > 0 || bAlwaysShowHours) { + strTemp.Format(_T("%02d:%02d:%02d"), rtVal.bHours, rtVal.bMinutes, rtVal.bSeconds); + } else { + strTemp.Format(_T("%02d:%02d"), rtVal.bMinutes, rtVal.bSeconds); + } + return strTemp; +} + +REFERENCE_TIME StringToReftime(LPCTSTR strVal) +{ + REFERENCE_TIME rt = 0; + int lHour = 0; + int lMinute = 0; + int lSecond = 0; + int lMillisec = 0; + + if (_stscanf_s (strVal, _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { + rt = ( (((lHour*24)+lMinute)*60 + lSecond) * MILLISECONDS + lMillisec ) * (UNITS/MILLISECONDS); + } + + return rt; +} + +const double Rec601_Kr = 0.299; +const double Rec601_Kb = 0.114; +const double Rec601_Kg = 0.587; +COLORREF YCrCbToRGB_Rec601(BYTE Y, BYTE Cr, BYTE Cb) +{ + + double rp = Y + 2*(Cr-128)*(1.0-Rec601_Kr); + double gp = Y - 2*(Cb-128)*(1.0-Rec601_Kb)*Rec601_Kb/Rec601_Kg - 2*(Cr-128)*(1.0-Rec601_Kr)*Rec601_Kr/Rec601_Kg; + double bp = Y + 2*(Cb-128)*(1.0-Rec601_Kb); + + return RGB (fabs(rp), fabs(gp), fabs(bp)); +} + +DWORD YCrCbToRGB_Rec601(BYTE A, BYTE Y, BYTE Cr, BYTE Cb) +{ + + double rp = Y + 2*(Cr-128)*(1.0-Rec601_Kr); + double gp = Y - 2*(Cb-128)*(1.0-Rec601_Kb)*Rec601_Kb/Rec601_Kg - 2*(Cr-128)*(1.0-Rec601_Kr)*Rec601_Kr/Rec601_Kg; + double bp = Y + 2*(Cb-128)*(1.0-Rec601_Kb); + + return D3DCOLOR_ARGB(A, (BYTE)fabs(rp), (BYTE)fabs(gp), (BYTE)fabs(bp)); +} + + +const double Rec709_Kr = 0.2125; +const double Rec709_Kb = 0.0721; +const double Rec709_Kg = 0.7154; + +COLORREF YCrCbToRGB_Rec709(BYTE Y, BYTE Cr, BYTE Cb) +{ + + double rp = Y + 2*(Cr-128)*(1.0-Rec709_Kr); + double gp = Y - 2*(Cb-128)*(1.0-Rec709_Kb)*Rec709_Kb/Rec709_Kg - 2*(Cr-128)*(1.0-Rec709_Kr)*Rec709_Kr/Rec709_Kg; + double bp = Y + 2*(Cb-128)*(1.0-Rec709_Kb); + + return RGB (fabs(rp), fabs(gp), fabs(bp)); +} + +DWORD YCrCbToRGB_Rec709(BYTE A, BYTE Y, BYTE Cr, BYTE Cb) +{ + + double rp = Y + 2*(Cr-128)*(1.0-Rec709_Kr); + double gp = Y - 2*(Cb-128)*(1.0-Rec709_Kb)*Rec709_Kb/Rec709_Kg - 2*(Cr-128)*(1.0-Rec709_Kr)*Rec709_Kr/Rec709_Kg; + double bp = Y + 2*(Cb-128)*(1.0-Rec709_Kb); + + return D3DCOLOR_ARGB (A, (BYTE)fabs(rp), (BYTE)fabs(gp), (BYTE)fabs(bp)); +} diff --git a/src/dsutil/DSUtil.h b/src/dsutil/DSUtil.h index 379af67..bdb4783 100644 --- a/src/dsutil/DSUtil.h +++ b/src/dsutil/DSUtil.h @@ -41,6 +41,8 @@ #include "vd.h" #include "text.h" +#define LCID_NOSUBTITLES -1 + extern void DumpStreamConfig(TCHAR* fn, IAMStreamConfig* pAMVSCCap); extern int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC); extern bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly = false); @@ -102,6 +104,8 @@ extern CStringW UTF8To16(LPCSTR utf8); extern CStringA UTF16To8(LPCWSTR utf16); extern CString ISO6391ToLanguage(LPCSTR code); extern CString ISO6392ToLanguage(LPCSTR code); +extern LCID ISO6391ToLcid(LPCSTR code); +extern LCID ISO6392ToLcid(LPCSTR code); extern CString ISO6391To6392(LPCSTR code); extern CString ISO6392To6391(LPCSTR code); extern CString LanguageToISO6392(LPCTSTR lang); @@ -113,6 +117,22 @@ extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue); extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext = NULL, ...); extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext = NULL, ...); extern void UnRegisterSourceFilter(const GUID& subtype); +extern LPCTSTR GetDXVAMode(const GUID* guidDecoder); +extern void DumpBuffer(BYTE* pBuffer, int nSize); +extern CString ReftimeToString(const REFERENCE_TIME& rtVal); +extern CString ReftimeToString2(const REFERENCE_TIME& rtVal); +extern CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours=false); +REFERENCE_TIME StringToReftime(LPCTSTR strVal); +extern COLORREF YCrCbToRGB_Rec601(BYTE Y, BYTE Cr, BYTE Cb); +extern COLORREF YCrCbToRGB_Rec709(BYTE Y, BYTE Cr, BYTE Cb); +extern DWORD YCrCbToRGB_Rec601(BYTE A, BYTE Y, BYTE Cr, BYTE Cb); +extern DWORD YCrCbToRGB_Rec709(BYTE A, BYTE Y, BYTE Cr, BYTE Cb); +extern void TraceFilterInfo(IBaseFilter* pBF); +extern void TracePinInfo(IPin* pPin); +extern void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName); +extern void HexDump(CString fName, BYTE* buf, int size); +extern DWORD GetDefChannelMask(WORD nChannels); +extern void CorrectComboListWidth(CComboBox& m_pComboBox); class CPinInfo : public PIN_INFO { @@ -196,3 +216,20 @@ static CUnknown* WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) if(punk == NULL) *phr = E_OUTOFMEMORY; return punk; } +#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } +#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +inline int LNKO(int a, int b) +{ + if(a == 0 || b == 0) { + return(1); + } + while(a != b) { + if(a < b) { + b -= a; + } else if(a > b) { + a -= b; + } + } + return(a); +} diff --git a/src/dsutil/GolombBuffer.cpp b/src/dsutil/GolombBuffer.cpp new file mode 100644 index 0000000..3508b96 --- /dev/null +++ b/src/dsutil/GolombBuffer.cpp @@ -0,0 +1,117 @@ +/* + * $Id: GolombBuffer.cpp 3526 2011-08-01 15:46:29Z XhmikosR $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#include "stdafx.h" +#include "GolombBuffer.h" + +CGolombBuffer::CGolombBuffer(BYTE* pBuffer, int nSize) +{ + m_pBuffer = pBuffer; + m_nSize = nSize; + + Reset(); +} + +UINT64 CGolombBuffer::BitRead(int nBits, bool fPeek) +{ + // ASSERT(nBits >= 0 && nBits <= 64); + + while(m_bitlen < nBits) { + m_bitbuff <<= 8; + + if (m_nBitPos >= m_nSize) { + return 0; + } + + *(BYTE*)&m_bitbuff = m_pBuffer[m_nBitPos++]; + m_bitlen += 8; + } + + int bitlen = m_bitlen - nBits; + + UINT64 ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); + + if(!fPeek) { + m_bitbuff &= ((1ui64 << bitlen) - 1); + m_bitlen = bitlen; + } + + return ret; +} + +UINT64 CGolombBuffer::UExpGolombRead() +{ + int n = -1; + for(BYTE b = 0; !b; n++) { + b = (BYTE)BitRead(1); + } + return (1ui64 << n) - 1 + BitRead(n); +} + +INT64 CGolombBuffer::SExpGolombRead() +{ + UINT64 k = UExpGolombRead(); + return ((k&1) ? 1 : -1) * ((k + 1) >> 1); +} + +void CGolombBuffer::BitByteAlign() +{ + m_bitlen &= ~7; +} + +__int64 CGolombBuffer::GetPos() +{ + return m_nBitPos - (m_bitlen>>3); +} + +void CGolombBuffer::ReadBuffer(BYTE* pDest, int nSize) +{ + ASSERT (m_nBitPos + nSize <= m_nSize); + ASSERT (m_bitlen == 0); + nSize = min (nSize, m_nSize - m_nBitPos); + + memcpy (pDest, m_pBuffer+m_nBitPos, nSize); + m_nBitPos += nSize; +} + +void CGolombBuffer::Reset() +{ + m_nBitPos = 0; + m_bitlen = 0; + m_bitbuff = 0; +} + +void CGolombBuffer::Reset(BYTE* pNewBuffer, int nNewSize) +{ + m_pBuffer = pNewBuffer; + m_nSize = nNewSize; + + Reset(); +} + +void CGolombBuffer::SkipBytes(int nCount) +{ + m_nBitPos += nCount; + m_bitlen = 0; + m_bitbuff = 0; +} diff --git a/src/dsutil/GolombBuffer.h b/src/dsutil/GolombBuffer.h new file mode 100644 index 0000000..0a7bbd7 --- /dev/null +++ b/src/dsutil/GolombBuffer.h @@ -0,0 +1,74 @@ +/* + * $Id: GolombBuffer.h 2533 2010-09-12 12:45:26Z xhmikosr $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +class CGolombBuffer +{ +public: + CGolombBuffer(BYTE* pBuffer, int nSize); + + UINT64 BitRead(int nBits, bool fPeek = false); + UINT64 UExpGolombRead(); + INT64 SExpGolombRead(); + void BitByteAlign(); + + inline BYTE ReadByte() { + return (BYTE) BitRead ( 8); + }; + inline SHORT ReadShort() { + return (SHORT)BitRead (16); + }; + inline DWORD ReadDword() { + return (DWORD)BitRead (32); + }; + void ReadBuffer(BYTE* pDest, int nSize); + + void Reset(); + void Reset(BYTE* pNewBuffer, int nNewSize); + + void SetSize(int nValue) { + m_nSize = nValue; + }; + int GetSize() const { + return m_nSize; + }; + int RemainingSize() const { + return m_nSize - m_nBitPos; + }; + bool IsEOF() const { + return m_nBitPos >= m_nSize; + }; + INT64 GetPos(); + BYTE* GetBufferPos() { + return m_pBuffer + m_nBitPos; + }; + + void SkipBytes(int nCount); + +private : + BYTE* m_pBuffer; + int m_nSize; + int m_nBitPos; + int m_bitlen; + INT64 m_bitbuff; +}; diff --git a/src/dsutil/H264Nalu.cpp b/src/dsutil/H264Nalu.cpp new file mode 100644 index 0000000..93a9663 --- /dev/null +++ b/src/dsutil/H264Nalu.cpp @@ -0,0 +1,108 @@ +/* + * $Id: H264Nalu.cpp 3827 2011-11-13 11:29:01Z Aleksoid $ + * + * (C) 2006-2011 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "stdafx.h" +#include "H264Nalu.h" + +CH264Nalu::CH264Nalu() +{ + // Explicit default constructor to make cppcheck happy. +} + +void CH264Nalu::SetBuffer(BYTE* pBuffer, int nSize, int nNALSize) +{ + m_pBuffer = pBuffer; + m_nSize = nSize; + m_nNALSize = nNALSize; + m_nCurPos = 0; + m_nNextRTP = 0; + + m_nNALStartPos = 0; + m_nNALDataPos = 0; + + if (nNALSize == 0) { + MoveToNextAnnexBStartcode(); + } +} + +bool CH264Nalu::MoveToNextAnnexBStartcode() +{ + int nBuffEnd = m_nSize - 4; + + for (int i=m_nCurPos; i= m_nSize) || (m_nCurPos<0)) { + return false; + } + + if ((m_nNALSize != 0) && (m_nCurPos == m_nNextRTP)) { + // RTP Nalu type : (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size + m_nNALStartPos = m_nCurPos; + m_nNALDataPos = m_nCurPos + m_nNALSize; + int nTemp = 0; + for (int i=0; i>7) & 1; + nal_reference_idc = (m_pBuffer[m_nNALDataPos]>>5) & 3; + nal_unit_type = (NALU_TYPE) (m_pBuffer[m_nNALDataPos] & 0x1f); + + return true; +} diff --git a/src/dsutil/H264Nalu.h b/src/dsutil/H264Nalu.h new file mode 100644 index 0000000..429a45a --- /dev/null +++ b/src/dsutil/H264Nalu.h @@ -0,0 +1,94 @@ +/* + * $Id: H264Nalu.h 3581 2011-08-05 16:26:10Z underground78 $ + * + * (C) 2006-2011 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + + +typedef enum { + NALU_TYPE_SLICE = 1, + NALU_TYPE_DPA = 2, + NALU_TYPE_DPB = 3, + NALU_TYPE_DPC = 4, + NALU_TYPE_IDR = 5, + NALU_TYPE_SEI = 6, + NALU_TYPE_SPS = 7, + NALU_TYPE_PPS = 8, + NALU_TYPE_AUD = 9, + NALU_TYPE_EOSEQ = 10, + NALU_TYPE_EOSTREAM = 11, + NALU_TYPE_FILL = 12 +} NALU_TYPE; + +class CH264Nalu +{ +private : + int forbidden_bit; //! should be always FALSE + int nal_reference_idc; //! NALU_PRIORITY_xxxx + NALU_TYPE nal_unit_type; //! NALU_TYPE_xxxx + + int m_nNALStartPos; //! NALU start (including startcode / size) + int m_nNALDataPos; //! Useful part + unsigned m_nDataLen; //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU) + + BYTE* m_pBuffer; + int m_nCurPos; + int m_nNextRTP; + int m_nSize; + int m_nNALSize; + + bool MoveToNextAnnexBStartcode(); + bool MoveToNextRTPStartcode(); + +public : + CH264Nalu(); + + NALU_TYPE GetType() const { + return nal_unit_type; + }; + bool IsRefFrame() const { + return (nal_reference_idc != 0); + }; + + int GetDataLength() const { + return m_nCurPos - m_nNALDataPos; + }; + BYTE* GetDataBuffer() { + return m_pBuffer + m_nNALDataPos; + }; + int GetRoundedDataLength() const { + int nSize = m_nCurPos - m_nNALDataPos; + return nSize + 128 - (nSize %128); + } + + int GetLength() const { + return m_nCurPos - m_nNALStartPos; + }; + BYTE* GetNALBuffer() { + return m_pBuffer + m_nNALStartPos; + }; + bool IsEOF() const { + return m_nCurPos >= m_nSize; + }; + + void SetBuffer (BYTE* pBuffer, int nSize, int nNALSize); + bool ReadNext(); +}; diff --git a/src/dsutil/HdmvClipInfo.cpp b/src/dsutil/HdmvClipInfo.cpp new file mode 100644 index 0000000..6a170cf --- /dev/null +++ b/src/dsutil/HdmvClipInfo.cpp @@ -0,0 +1,468 @@ +/* + * $Id: HdmvClipInfo.cpp 3891 2011-12-12 00:10:53Z Aleksoid $ + * + * (C) 2006-2011 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "stdafx.h" +#include "HdmvClipInfo.h" +#include "DSUtil.h" + +extern LCID ISO6392ToLcid(LPCSTR code); + +CHdmvClipInfo::CHdmvClipInfo(void) +{ + m_hFile = INVALID_HANDLE_VALUE; + m_bIsHdmv = false; +} + +CHdmvClipInfo::~CHdmvClipInfo() +{ + CloseFile(S_OK); +} + +HRESULT CHdmvClipInfo::CloseFile(HRESULT hr) +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } + return hr; +} + +DWORD CHdmvClipInfo::ReadDword() +{ + return ReadByte()<<24 | ReadByte()<<16 | ReadByte()<<8 | ReadByte(); +} + +SHORT CHdmvClipInfo::ReadShort() +{ + return ReadByte()<<8 | ReadByte(); +} + +BYTE CHdmvClipInfo::ReadByte() +{ + BYTE bVal; + DWORD dwRead; + ReadFile (m_hFile, &bVal, sizeof(bVal), &dwRead, NULL); + + return bVal; +} + +void CHdmvClipInfo::ReadBuffer(BYTE* pBuff, DWORD nLen) +{ + DWORD dwRead; + ReadFile (m_hFile, pBuff, nLen, &dwRead, NULL); +} + +HRESULT CHdmvClipInfo::ReadProgramInfo() +{ + BYTE number_of_program_sequences; + BYTE number_of_streams_in_ps; + DWORD dwPos; + + m_Streams.RemoveAll(); + SetFilePointer (m_hFile, ProgramInfo_start_address, NULL, FILE_BEGIN); + + ReadDword(); //length + ReadByte(); //reserved_for_word_align + number_of_program_sequences = (BYTE)ReadByte(); + int iStream = 0; + for (size_t i=0; i> 4); + BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf); + Temp = ReadByte(); + BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4); + + m_Streams[iStream].m_VideoFormat = VideoFormat; + m_Streams[iStream].m_FrameRate = FrameRate; + m_Streams[iStream].m_AspectRatio = AspectRatio; + } + break; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + case AUDIO_STREAM_LPCM: + case AUDIO_STREAM_AC3: + case AUDIO_STREAM_DTS: + case AUDIO_STREAM_AC3_TRUE_HD: + case AUDIO_STREAM_AC3_PLUS: + case AUDIO_STREAM_DTS_HD: + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + case SECONDARY_AUDIO_AC3_PLUS: + case SECONDARY_AUDIO_DTS_HD: { + uint8 Temp = ReadByte(); + BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); + BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF); + + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LCID = ISO6392ToLcid (m_Streams[iStream].m_LanguageCode); + m_Streams[iStream].m_ChannelLayout = ChannelLayout; + m_Streams[iStream].m_SampleRate = SampleRate; + } + break; + case PRESENTATION_GRAPHICS_STREAM: + case INTERACTIVE_GRAPHICS_STREAM: { + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LCID = ISO6392ToLcid (m_Streams[iStream].m_LanguageCode); + } + break; + case SUBTITLE_STREAM: { + ReadByte(); // Should this really be here? + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LCID = ISO6392ToLcid (m_Streams[iStream].m_LanguageCode); + } + break; + default : + break; + } + + iStream++; + SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN); + } + } + return S_OK; +} + +HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile) +{ + BYTE Buff[100]; + + m_bIsHdmv = false; + m_hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + if(m_hFile != INVALID_HANDLE_VALUE) { + ReadBuffer(Buff, 4); + if (memcmp (Buff, "HDMV", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp (Buff, "0200", 4)!=0) && (memcmp (Buff, "0100", 4)!=0)) { + return CloseFile (VFW_E_INVALID_FILE_FORMAT); + } + + SequenceInfo_start_address = ReadDword(); + ProgramInfo_start_address = ReadDword(); + + ReadProgramInfo(); + + m_bIsHdmv = true; + + return CloseFile(S_OK); + } + + return AmHresultFromWin32(GetLastError()); +} + +CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(SHORT wPID) +{ + size_t nStreams = m_Streams.GetCount(); + for (size_t i=0; i& Playlist) +{ + + BYTE Buff[100]; + CPath Path (strPlaylistFile); + bool bDuplicate = false; + rtDuration = 0; + + // Get BDMV folder + Path.RemoveFileSpec(); + Path.RemoveFileSpec(); + + m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + if(m_hFile != INVALID_HANDLE_VALUE) { + ReadBuffer(Buff, 4); + if (memcmp (Buff, "MPLS", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp (Buff, "0200", 4)!=0) && (memcmp (Buff, "0100", 4)!=0)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + DWORD dwPos; + DWORD dwTemp; + USHORT nPlaylistItems; + + dwPos = ReadDword(); // PlayList_start_address + ReadDword(); // PlayListMark_start_address + + // PlayList() + SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN); + ReadDword(); // length + ReadShort(); // reserved_for_future_use + nPlaylistItems = ReadShort(); // number_of_PlayItems + ReadShort(); // number_of_SubPaths + + dwPos += 10; + for (size_t i=0; i33 bits! + + dwTemp = ReadDword(); + Item.m_rtOut = 20000i64*dwTemp/90; // Carefull : 32->33 bits! + + rtDuration += (Item.m_rtOut - Item.m_rtIn); + + if (Playlist.Find(Item) != NULL) { + bDuplicate = true; + } + Playlist.AddTail (Item); + + //TRACE ("File : %S, Duration : %S, Total duration : %S\n", strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration)); + } + + CloseFile (S_OK); + return bDuplicate ? S_FALSE : S_OK; + } + + return AmHresultFromWin32(GetLastError()); +} + +HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters) +{ + BYTE Buff[100]; + CPath Path (strPlaylistFile); + bool bDuplicate = false; + + // Get BDMV folder + Path.RemoveFileSpec(); + Path.RemoveFileSpec(); + + m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + if(m_hFile != INVALID_HANDLE_VALUE) + { + REFERENCE_TIME* rtOffset = new REFERENCE_TIME[PlaylistItems.GetCount()]; + REFERENCE_TIME rtSum = 0; + int nIndex = 0; + + POSITION pos = PlaylistItems.GetHeadPosition(); + while(pos) + { + CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos); + + rtOffset[nIndex] = rtSum - PI.m_rtIn; + rtSum = rtSum + PI.Duration(); + nIndex++; + } + + ReadBuffer(Buff, 4); + if (memcmp (Buff, "MPLS", 4)) { + SAFE_DELETE_ARRAY(rtOffset); + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp (Buff, "0200", 4)!=0) && (memcmp (Buff, "0100", 4)!=0)) { + SAFE_DELETE_ARRAY(rtOffset); + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + DWORD dwPos; + USHORT nMarkCount; + + ReadDword(); // PlayList_start_address + dwPos = ReadDword(); // PlayListMark_start_address + + // PlayListMark() + SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN); + ReadDword(); // length + nMarkCount = ReadShort(); // number_of_PlayList_marks + for (size_t i=0; i& MainPlaylist, CAtlList& MPLSPlaylists) +{ + HRESULT hr = E_FAIL; + + CString strPath (strFolder); + CString strFilter; + + MPLSPlaylists.RemoveAll(); + + CAtlList Playlist; + WIN32_FIND_DATA fd = {0}; + + strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); + strPath.Replace(_T("\\STREAM\\"), _T("\\")); + strPath += _T("\\BDMV\\"); + strFilter.Format (_T("%sPLAYLIST\\*.mpls"), strPath); + + HANDLE hFind = FindFirstFile(strFilter, &fd); + if(hFind != INVALID_HANDLE_VALUE) { + REFERENCE_TIME rtMax = 0; + REFERENCE_TIME rtCurrent; + CString strCurrentPlaylist; + do { + strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath, fd.cFileName); + Playlist.RemoveAll(); + + // Main movie shouldn't have duplicate M2TS filename... + if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) { + if(rtCurrent > rtMax) { + rtMax = rtCurrent; + strPlaylistFile = strCurrentPlaylist; + MainPlaylist.RemoveAll(); + POSITION pos = Playlist.GetHeadPosition(); + while(pos) { + MainPlaylist.AddTail(Playlist.GetNext(pos)); + } + hr = S_OK; + } + if(rtCurrent >= (REFERENCE_TIME)MIN_LIMIT*600000000) { + PlaylistItem Item; + Item.m_strFileName = strCurrentPlaylist; + Item.m_rtIn = 0; + Item.m_rtOut = rtCurrent; + MPLSPlaylists.AddTail(Item); + } + + } + } while(FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + if(MPLSPlaylists.GetCount() > 1) { + // bubble sort + for (size_t j=0; j. + * + */ + +#pragma once + +#include "Mpeg2Def.h" + +enum BDVM_VideoFormat { + BDVM_VideoFormat_Unknown = 0, + BDVM_VideoFormat_480i = 1, + BDVM_VideoFormat_576i = 2, + BDVM_VideoFormat_480p = 3, + BDVM_VideoFormat_1080i = 4, + BDVM_VideoFormat_720p = 5, + BDVM_VideoFormat_1080p = 6, + BDVM_VideoFormat_576p = 7, +}; + +enum BDVM_FrameRate { + BDVM_FrameRate_Unknown = 0, + BDVM_FrameRate_23_976 = 1, + BDVM_FrameRate_24 = 2, + BDVM_FrameRate_25 = 3, + BDVM_FrameRate_29_97 = 4, + BDVM_FrameRate_50 = 6, + BDVM_FrameRate_59_94 = 7 +}; + +enum BDVM_AspectRatio { + BDVM_AspectRatio_Unknown = 0, + BDVM_AspectRatio_4_3 = 2, + BDVM_AspectRatio_16_9 = 3, + BDVM_AspectRatio_2_21 = 4 +}; + +enum BDVM_ChannelLayout { + BDVM_ChannelLayout_Unknown = 0, + BDVM_ChannelLayout_MONO = 1, + BDVM_ChannelLayout_STEREO = 3, + BDVM_ChannelLayout_MULTI = 6, + BDVM_ChannelLayout_COMBO = 12 +}; + +enum BDVM_SampleRate { + BDVM_SampleRate_Unknown = 0, + BDVM_SampleRate_48 = 1, + BDVM_SampleRate_96 = 4, + BDVM_SampleRate_192 = 5, + BDVM_SampleRate_48_192 = 12, + BDVM_SampleRate_48_96 = 14 +}; + +typedef unsigned char uint8; +typedef signed char int8; + +typedef unsigned short uint16; +typedef short int16; + +typedef unsigned long uint32; +typedef long int32; + + +class CHdmvClipInfo +{ +public: + + struct Stream { + Stream() { + memset(this, 0, sizeof(*this)); + } + SHORT m_PID; + PES_STREAM_TYPE m_Type; + char m_LanguageCode[4]; + LCID m_LCID; + + // Valid for video types + BDVM_VideoFormat m_VideoFormat; + BDVM_FrameRate m_FrameRate; + BDVM_AspectRatio m_AspectRatio; + // Valid for audio types + BDVM_ChannelLayout m_ChannelLayout; + BDVM_SampleRate m_SampleRate; + + LPCTSTR Format(); + }; + + struct PlaylistItem { + CString m_strFileName; + REFERENCE_TIME m_rtIn; + REFERENCE_TIME m_rtOut; + + REFERENCE_TIME Duration() const { + return m_rtOut - m_rtIn; + } + + bool operator == (const PlaylistItem& pi) const { + return pi.m_strFileName == m_strFileName; + } + }; + + enum PlaylistMarkType + { + Reserved = 0x00, + EntryMark = 0x01, + LinkPoint = 0x02 + }; + + struct PlaylistChapter + { + SHORT m_nPlayItemId; + PlaylistMarkType m_nMarkType; + REFERENCE_TIME m_rtTimestamp; + SHORT m_nEntryPID; + REFERENCE_TIME m_rtDuration; + }; + + CHdmvClipInfo(void); + ~CHdmvClipInfo(); + + HRESULT ReadInfo(LPCTSTR strFile); + Stream* FindStream(SHORT wPID); + bool IsHdmv() const { + return m_bIsHdmv; + }; + size_t GetStreamNumber() { + return m_Streams.GetCount(); + }; + Stream* GetStreamByIndex(size_t nIndex) { + return (nIndex < m_Streams.GetCount()) ? &m_Streams[nIndex] : NULL; + }; + + HRESULT FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, CAtlList& MainPlaylist, CAtlList& MPLSPlaylists); + HRESULT ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, CAtlList& Playlist); + HRESULT ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters); + +private : + DWORD SequenceInfo_start_address; + DWORD ProgramInfo_start_address; + + HANDLE m_hFile; + + + CAtlArray m_Streams; + bool m_bIsHdmv; + + DWORD ReadDword(); + SHORT ReadShort(); + BYTE ReadByte(); + void ReadBuffer(BYTE* pBuff, DWORD nLen); + + HRESULT ReadProgramInfo(); + HRESULT CloseFile(HRESULT hr); +}; diff --git a/src/dsutil/Mpeg2Def.h b/src/dsutil/Mpeg2Def.h new file mode 100644 index 0000000..d69541e --- /dev/null +++ b/src/dsutil/Mpeg2Def.h @@ -0,0 +1,157 @@ +/* + * $Id: Mpeg2Def.h 3526 2011-08-01 15:46:29Z XhmikosR $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + + +enum PES_STREAM_TYPE { + INVALID = 0, + VIDEO_STREAM_MPEG1 = 0x01, + VIDEO_STREAM_MPEG2 = 0x02, // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream + AUDIO_STREAM_MPEG1 = 0x03, // all layers including mp3 (ISO/IEC 11172-3 Audio) + AUDIO_STREAM_MPEG2 = 0x04, // ISO/IEC 13818-3 Audio + PRIVATE = 0x05, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections + PES_PRIVATE = 0x06, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data + PES_07 = 0x07, // ISO/IEC 13522 MHEG + PES_08 = 0x08, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC + PES_09 = 0x09, // ITU-T Rec. H.222.1 + PES_0a = 0x0a, // ISO/IEC 13818-6 type A + PES_0b = 0x0b, // ISO/IEC 13818-6 type B + PES_0c = 0x0c, // ISO/IEC 13818-6 type C + PES_0d = 0x0d, // ISO/IEC 13818-6 type D + PES_0e = 0x0e, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary + PES_0f = 0x0f, // ISO/IEC 13818-7 Audio with ADTS transport syntax + PES_10 = 0x10, // ISO/IEC 14496-2 Visual + AUDIO_STREAM_AAC_LATM = 0x11, // ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1 + PES_12 = 0x12, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets + PES_13 = 0x13, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections. + PES_14 = 0x14, // ISO/IEC 13818-6 Synchronized Download Protocol + METADATA_PES_PACKETS = 0x15, // Metadata carried in PES packets + METADATA_SECTIONS = 0X16, // Metadata carried in metadata_sections + DATA_CAROUSEL = 0x17, // Metadata carried in ISO/IEC 13818-6 Data Carousel + OBJECT_CAROUSEL = 0x18, // Metadata carried in ISO/IEC 13818-6 Object Carousel + SYNCHRONIZED_DOWNLOAD = 0x19, // Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol + IPMP = 0x1A, // IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) + VIDEO_STREAM_H264 = 0x1B, // AVC video stream conforming to one or more profiles defined in Annex A of ITU-T Rec. H.264 + PES_1C = 0x1C, // ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS + TEXT = 0x1D, // ISO/IEC 14496-17 Text + AUXILIARY_VIDEO_STREAM = 0x1E, // Auxiliary video stream as defined in ISO/IEC 23002-3 + SVC_H264 = 0x1F, // SVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex G of ITU-T Rec. H.264 | ISO/IEC 14496-10 + MVC_H264 = 0x20, // MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 + AUDIO_STREAM_LPCM = 0x80, + AUDIO_STREAM_AC3 = 0x81, + AUDIO_STREAM_DTS = 0x82, + AUDIO_STREAM_AC3_TRUE_HD = 0x83, + AUDIO_STREAM_AC3_PLUS = 0x84, + AUDIO_STREAM_DTS_HD = 0x85, + AUDIO_STREAM_DTS_HD_MASTER_AUDIO = 0x86, + PRESENTATION_GRAPHICS_STREAM = 0x90, + INTERACTIVE_GRAPHICS_STREAM = 0x91, + SUBTITLE_STREAM = 0x92, + SECONDARY_AUDIO_AC3_PLUS = 0xa1, + SECONDARY_AUDIO_DTS_HD = 0xa2, + VIDEO_STREAM_VC1 = 0xea +}; + +enum MPEG2_PID { + PID_PAT = 0x000, // Program Association Table + PID_CAT = 0x001, // Conditional Access Table + PID_TSDT = 0x002, // Transport Stream Description Table + PID_NIT = 0x010, // Network Identification Table + PID_BAT = 0x011, // Bouquet Association Table ou ... + PID_SDT = 0x011, // Service Description Table + PID_EIT = 0x012, // Event Information Table + PID_RST = 0x013, // Running Status Tection + PID_TDT = 0x014, // Time and Date Table ou ... + PID_TOT = 0x014, // Time Offset Table + PID_SFN = 0x015, // SFN/MIP synchronisation + PID_DIT = 0x01e, + PID_SIT = 0x01f, + PID_NULL = 0x1fff // Null packet +}; + +enum DVB_SI { + SI_undef = -1, + SI_PAT = 0x00, + SI_CAT = 0x01, + SI_PMT = 0x02, + SI_DSMCC_a = 0x3a, + SI_DSMCC_b = 0x3b, + SI_DSMCC_c = 0x3c, + SI_DSMCC_d = 0x3d, + SI_DSMCC_e = 0x3e, + SI_DSMCC_f = 0x3f, + SI_NIT = 0x40, + SI_SDT = 0x42, + SI_EIT_act = 0x4e, + SI_EIT_oth = 0x4f, + SI_EIT_as0, SI_EIT_as1, SI_EIT_as2, SI_EIT_as3, SI_EIT_as4, SI_EIT_as5, SI_EIT_as6, SI_EIT_as7, + SI_EIT_as8, SI_EIT_as9, SI_EIT_asa, SI_EIT_asb, SI_EIT_asc, SI_EIT_asd, SI_EIT_ase, SI_EIT_asf, + SI_EIT_os0, SI_EIT_os1, SI_EIT_os2, SI_EIT_os3, SI_EIT_os4, SI_EIT_os5, SI_EIT_os6, SI_EIT_os7, + SI_EIT_os8, SI_EIT_os9, SI_EIT_osa, SI_EIT_osb, SI_EIT_osc, SI_EIT_osd, SI_EIT_ose, SI_EIT_osf +}; + +enum MPEG2_DESCRIPTOR { + // http://www.coolstf.com/tsreader/descriptors.html + DT_VIDEO_STREAM = 0x02, + DT_AUDIO_STREAM = 0x03, + DT_HIERARCHY = 0x04, + DT_REGISTRATION = 0x05, + DT_DATA_STREAM_ALIGNMENT = 0x06, + DT_TARGET_BACKGROUND_GRID = 0x07, + DT_VIDEO_WINDOW = 0x08, + DT_CONDITIONAL_ACCESS = 0x09, + DT_ISO_639_LANGUAGE = 0x0a, + DT_SYSTEM_CLOCK = 0x0b, + DT_MULTIPLEX_BUFFER_UTIL = 0x0c, + DT_COPYRIGHT_DESCRIPTOR = 0x0d, + DT_MAXIMUM_BITRATE = 0x0e, + DT_PRIVATE_DATA_INDICATOR = 0x0f, + DT_SMOOTHING_BUFFER = 0x10, + DT_STD = 0x11, // System Target Decoder ? + DT_IBP = 0x12, + DT_NETWORK_NAME = 0x40, + DT_SERVICE_LIST = 0x41, + DT_VBI_DATA = 0x45, + DT_SERVICE = 0x48, + DT_LINKAGE = 0x4a, + DT_SHORT_EVENT = 0x4d, + DT_EXTENDED_EVENT = 0x4e, + DT_COMPONENT = 0x50, + DT_STREAM_IDENTIFIER = 0x52, + DT_CONTENT = 0x54, + DT_PARENTAL_RATING = 0x55, + DT_TELETEXT = 0x56, + DT_SUBTITLING = 0x59, + DT_TERRESTRIAL_DELIV_SYS = 0x5a, + DT_PRIVATE_DATA = 0x5f, + // + DT_DATA_BROADCAST_ID = 0x66, + DT_AC3_AUDIO = 0x6a, // DVB + DT_EXTENDED_AC3_AUDIO = 0x7a, + // + DT_AC3_AUDIO__2 = 0x81, // DCII ou ATSC + DT_LOGICAL_CHANNEL = 0x83, + DT_HD_SIMCAST_LOG_CHANNEL = 0x88 +}; + +extern const wchar_t *StreamTypeToName(PES_STREAM_TYPE _Type); diff --git a/src/dsutil/dsutil_vs2010.vcxproj b/src/dsutil/dsutil_vs2010.vcxproj index 7d4adc6..0498235 100644 --- a/src/dsutil/dsutil_vs2010.vcxproj +++ b/src/dsutil/dsutil_vs2010.vcxproj @@ -122,6 +122,9 @@ + + + @@ -136,8 +139,12 @@ + + + + diff --git a/src/dsutil/dsutil_vs2010.vcxproj.filters b/src/dsutil/dsutil_vs2010.vcxproj.filters index 8bc4cbc..290ceda 100644 --- a/src/dsutil/dsutil_vs2010.vcxproj.filters +++ b/src/dsutil/dsutil_vs2010.vcxproj.filters @@ -42,6 +42,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -74,6 +83,18 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + diff --git a/src/subtitles/BaseSub.cpp b/src/subtitles/BaseSub.cpp new file mode 100644 index 0000000..9c97534 --- /dev/null +++ b/src/subtitles/BaseSub.cpp @@ -0,0 +1,33 @@ +/* + * $Id: BaseSub.cpp 2585 2010-09-18 12:39:20Z xhmikosr $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "stdafx.h" +#include "BaseSub.h" + +CBaseSub::CBaseSub(SUBTITLE_TYPE nType) + : m_nType(nType) +{ +} + +CBaseSub::~CBaseSub() +{ +} \ No newline at end of file diff --git a/src/subtitles/BaseSub.h b/src/subtitles/BaseSub.h new file mode 100644 index 0000000..7a7a171 --- /dev/null +++ b/src/subtitles/BaseSub.h @@ -0,0 +1,53 @@ +/* + * $Id: BaseSub.h 2786 2010-12-17 16:42:55Z XhmikosR $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#pragma once + +#include "CompositionObject.h" + +enum SUBTITLE_TYPE { + ST_DVB, + ST_HDMV +}; + +class CBaseSub +{ +public: + + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + + CBaseSub(SUBTITLE_TYPE nType); + virtual ~CBaseSub(); + + virtual HRESULT ParseSample (IMediaSample* pSample) = NULL; + virtual void Reset() = NULL; + virtual POSITION GetStartPosition(REFERENCE_TIME rt, double fps) = NULL; + virtual POSITION GetNext(POSITION pos) = NULL; + virtual REFERENCE_TIME GetStart(POSITION nPos) = NULL; + virtual REFERENCE_TIME GetStop(POSITION nPos) = NULL; + virtual void Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox) = NULL; + virtual HRESULT GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) = NULL; + +protected : + SUBTITLE_TYPE m_nType; +}; diff --git a/src/subtitles/CompositionObject.cpp b/src/subtitles/CompositionObject.cpp new file mode 100644 index 0000000..e547761 --- /dev/null +++ b/src/subtitles/CompositionObject.cpp @@ -0,0 +1,354 @@ +/* + * $Id: CompositionObject.cpp 3056 2011-04-29 21:07:44Z nevcairiel $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "stdafx.h" +#include "CompositionObject.h" +#include "../DSUtil/GolombBuffer.h" + + + +CompositionObject::CompositionObject() +{ + m_rtStart = 0; + m_rtStop = 0; + m_pRLEData = NULL; + m_nRLEDataSize = 0; + m_nRLEPos = 0; + m_nColorNumber = 0; + memsetd (m_Colors, 0xFF000000, sizeof(m_Colors)); +} + +CompositionObject::~CompositionObject() +{ + delete[] m_pRLEData; +} + +void CompositionObject::SetPalette (int nNbEntry, HDMV_PALETTE* pPalette, bool bIsHD) +{ + m_nColorNumber = nNbEntry; + + for (int i=0; i 0) { + nPaletteIndex = 0; + } + } else { + nCount = (bSwitch&0x3F) <<8 | (SHORT)GBuffer.ReadByte(); + nPaletteIndex = 0; + } + } else { + if (!(bSwitch & 0x40)) { + nCount = bSwitch & 0x3F; + nPaletteIndex = GBuffer.ReadByte(); + } else { + nCount = (bSwitch&0x3F) <<8 | (SHORT)GBuffer.ReadByte(); + nPaletteIndex = GBuffer.ReadByte(); + } + } + } + + if (nCount>0) { + if (nPaletteIndex != 0xFF) { // Fully transparent (�9.14.4.2.2.1.1) + FillSolidRect (spd, nX, nY, nCount, 1, m_Colors[nPaletteIndex]); + } + nX += nCount; + } else { + nY++; + nX = m_horizontal_position; + } + } +} + + +void CompositionObject::RenderDvb(SubPicDesc& spd, SHORT nX, SHORT nY) +{ + if (!m_pRLEData) { + return; + } + + CGolombBuffer gb (m_pRLEData, m_nRLEDataSize); + SHORT sTopFieldLength; + SHORT sBottomFieldLength; + + sTopFieldLength = gb.ReadShort(); + sBottomFieldLength = gb.ReadShort(); + + DvbRenderField (spd, gb, nX, nY, sTopFieldLength); + DvbRenderField (spd, gb, nX, nY+1, sBottomFieldLength); +} + + +void CompositionObject::DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, SHORT nXStart, SHORT nYStart, SHORT nLength) +{ + //FillSolidRect (spd, 0, 0, 300, 10, 0xFFFF0000); // Red opaque + //FillSolidRect (spd, 0, 10, 300, 10, 0xCC00FF00); // Green 80% + //FillSolidRect (spd, 0, 20, 300, 10, 0x100000FF); // Blue 60% + //return; + SHORT nX = nXStart; + SHORT nY = nYStart; + INT64 nEnd = gb.GetPos()+nLength; + while (gb.GetPos() < nEnd) { + BYTE bType = gb.ReadByte(); + switch (bType) { + case 0x10 : + Dvb2PixelsCodeString(spd, gb, nX, nY); + break; + case 0x11 : + Dvb4PixelsCodeString(spd, gb, nX, nY); + break; + case 0x12 : + Dvb8PixelsCodeString(spd, gb, nX, nY); + break; + case 0x20 : + gb.SkipBytes (2); + break; + case 0x21 : + gb.SkipBytes (4); + break; + case 0x22 : + gb.SkipBytes (16); + break; + case 0xF0 : + nX = nXStart; + nY += 2; + break; + default : + ASSERT(FALSE); + break; + } + } +} + + +void CompositionObject::Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, SHORT& nX, SHORT& nY) +{ + BYTE bTemp; + BYTE nPaletteIndex = 0; + SHORT nCount; + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + nCount = 0; + nPaletteIndex = 0; + bTemp = (BYTE)gb.BitRead(2); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 1) { // switch_1 + nCount = 3 + (SHORT)gb.BitRead(3); // run_length_3-9 + nPaletteIndex = (BYTE)gb.BitRead(2); + } else { + if (gb.BitRead(1) == 0) { // switch_2 + switch (gb.BitRead(2)) { // switch_3 + case 0 : + bQuit = true; + break; + case 1 : + nCount = 2; + break; + case 2 : // if (switch_3 == '10') + nCount = 12 + (SHORT)gb.BitRead(4); // run_length_12-27 + nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code + break; + case 3 : + nCount = 29 + gb.ReadByte(); // run_length_29-284 + nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code + break; + } + } else { + nCount = 1; + } + } + } + + if (nX+nCount > m_width) { + ASSERT (FALSE); + break; + } + + if (nCount>0) { + FillSolidRect (spd, nX, nY, nCount, 1, m_Colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} + +void CompositionObject::Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, SHORT& nX, SHORT& nY) +{ + BYTE bTemp; + BYTE nPaletteIndex = 0; + SHORT nCount; + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + nCount = 0; + nPaletteIndex = 0; + bTemp = (BYTE)gb.BitRead(4); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 0) { // switch_1 + nCount = (SHORT)gb.BitRead(3); // run_length_3-9 + if (nCount != 0) { + nCount += 2; + } else { + bQuit = true; + } + } else { + if (gb.BitRead(1) == 0) { // switch_2 + nCount = 4 + (SHORT)gb.BitRead(2); // run_length_4-7 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + } else { + switch (gb.BitRead(2)) { // switch_3 + case 0 : + nCount = 1; + break; + case 1 : + nCount = 2; + break; + case 2 : // if (switch_3 == '10') + nCount = 9 + (SHORT)gb.BitRead(4); // run_length_9-24 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + break; + case 3 : + nCount = 25 + gb.ReadByte(); // run_length_25-280 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + break; + } + } + } + } + + if (nX+nCount > m_width) { + ASSERT (FALSE); + break; + } + + if (nCount>0) { + FillSolidRect (spd, nX, nY, nCount, 1, m_Colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} + +void CompositionObject::Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, SHORT& nX, SHORT& nY) +{ + BYTE bTemp; + BYTE nPaletteIndex = 0; + SHORT nCount; + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + nCount = 0; + nPaletteIndex = 0; + bTemp = gb.ReadByte(); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 0) { // switch_1 + nCount = (SHORT)gb.BitRead(7); // run_length_1-127 + if (nCount == 0) { + bQuit = true; + } + } else { + nCount = (SHORT)gb.BitRead(7); // run_length_3-127 + nPaletteIndex = gb.ReadByte(); + } + } + + if (nX+nCount > m_width) { + ASSERT (FALSE); + break; + } + + if (nCount>0) { + FillSolidRect (spd, nX, nY, nCount, 1, m_Colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} diff --git a/src/subtitles/CompositionObject.h b/src/subtitles/CompositionObject.h new file mode 100644 index 0000000..926eb58 --- /dev/null +++ b/src/subtitles/CompositionObject.h @@ -0,0 +1,93 @@ +/* + * $Id: CompositionObject.h 3720 2011-09-12 00:30:00Z aleksoid $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#pragma once + +#include "Rasterizer.h" + + +struct HDMV_PALETTE { + BYTE entry_id; + BYTE Y; + BYTE Cr; + BYTE Cb; + BYTE T; // HDMV rule : 0 transparent, 255 opaque (compatible DirectX) +}; + +class CGolombBuffer; + +class CompositionObject : Rasterizer +{ +public : + SHORT m_object_id_ref; + BYTE m_window_id_ref; + bool m_object_cropped_flag; + bool m_forced_on_flag; + BYTE m_version_number; + BYTE m_nObjectNumber; + + SHORT m_horizontal_position; + SHORT m_vertical_position; + SHORT m_width; + SHORT m_height; + + SHORT m_cropping_horizontal_position; + SHORT m_cropping_vertical_position; + SHORT m_cropping_width; + SHORT m_cropping_height; + + REFERENCE_TIME m_rtStart; + REFERENCE_TIME m_rtStop; + + CompositionObject(); + ~CompositionObject(); + + void SetRLEData(BYTE* pBuffer, int nSize, int nTotalSize); + void AppendRLEData(BYTE* pBuffer, int nSize); + int GetRLEDataSize() { + return m_nRLEDataSize; + }; + bool IsRLEComplete() { + return m_nRLEPos >= m_nRLEDataSize; + }; + void RenderHdmv(SubPicDesc& spd); + void RenderDvb(SubPicDesc& spd, SHORT nX, SHORT nY); + void WriteSeg (SubPicDesc& spd, SHORT nX, SHORT nY, SHORT nCount, SHORT nPaletteIndex); + void SetPalette (int nNbEntry, HDMV_PALETTE* pPalette, bool bIsHD); + void SetPalette (int nNbEntry, DWORD* dwColors); + bool HavePalette() { + return m_nColorNumber>0; + }; + +private : + BYTE* m_pRLEData; + int m_nRLEDataSize; + int m_nRLEPos; + int m_nColorNumber; + DWORD m_Colors[256]; + + void DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, SHORT nXStart, SHORT nYStart, SHORT nLength); + void Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, SHORT& nX, SHORT& nY); + void Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, SHORT& nX, SHORT& nY); + void Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, SHORT& nX, SHORT& nY); +}; diff --git a/src/subtitles/DVBSub.cpp b/src/subtitles/DVBSub.cpp new file mode 100644 index 0000000..54c5891 --- /dev/null +++ b/src/subtitles/DVBSub.cpp @@ -0,0 +1,564 @@ +/* + * $Id: DVBSub.cpp 3605 2011-08-07 19:52:16Z underground78 $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#include "stdafx.h" +#include "DVBSub.h" +#include "../DSUtil/GolombBuffer.h" + +#if (1) // Set to 1 to activate DVB subtitles traces +#define TRACE_DVB TRACE +#else +#define TRACE_DVB +#endif + +#define BUFFER_CHUNK_GROW 0x1000 + +CDVBSub::CDVBSub(void) + : CBaseSub(ST_DVB) +{ + m_nBufferReadPos = 0; + m_nBufferWritePos = 0; + m_nBufferSize = 0; + m_pBuffer = NULL; +} + +CDVBSub::~CDVBSub(void) +{ + Reset(); + SAFE_DELETE(m_pBuffer); +} + +CDVBSub::DVB_PAGE* CDVBSub::FindPage(REFERENCE_TIME rt) +{ + POSITION pos = m_Pages.GetHeadPosition(); + + while (pos) { + DVB_PAGE* pPage = m_Pages.GetAt (pos); + + if (rt >= pPage->rtStart && rt < pPage->rtStop) { + return pPage; + } + + m_Pages.GetNext(pos); + } + + return NULL; +} + +CDVBSub::DVB_REGION* CDVBSub::FindRegion(DVB_PAGE* pPage, BYTE bRegionId) +{ + if (pPage != NULL) { + for (int i=0; iRegionCount; i++) { + if (pPage->Regions[i].Id == bRegionId) { + return &pPage->Regions[i]; + } + } + } + return NULL; +} + +CDVBSub::DVB_CLUT* CDVBSub::FindClut(DVB_PAGE* pPage, BYTE bClutId) +{ + if (pPage != NULL) { + for (int i=0; iRegionCount; i++) { + if (pPage->Regions[i].CLUT_id == bClutId) { + return &pPage->Regions[i].Clut; + } + } + } + return NULL; +} + +CompositionObject* CDVBSub::FindObject(DVB_PAGE* pPage, SHORT sObjectId) +{ + if (pPage != NULL) { + POSITION pos = pPage->Objects.GetHeadPosition(); + + while (pos) { + CompositionObject* pObject = pPage->Objects.GetAt (pos); + + if (pObject->m_object_id_ref == sObjectId) { + return pObject; + } + + pPage->Objects.GetNext(pos); + } + } + return NULL; +} + +HRESULT CDVBSub::AddToBuffer(BYTE* pData, int nSize) +{ + bool bFirstChunk = (*((LONG*)pData) & 0x00FFFFFF) == 0x000f0020; // DVB sub start with 0x20 0x00 0x0F ... + + if (m_nBufferWritePos > 0 || bFirstChunk) { + if (bFirstChunk) { + m_nBufferWritePos = 0; + m_nBufferReadPos = 0; + } + + if (m_nBufferWritePos+nSize > m_nBufferSize) { + if (m_nBufferWritePos+nSize > 20*BUFFER_CHUNK_GROW) { + // Too big to be a DVB sub ! + TRACE_DVB ("DVB - Too much data receive...\n"); + ASSERT (FALSE); + + Reset(); + return E_INVALIDARG; + } + + BYTE* pPrev = m_pBuffer; + m_nBufferSize = max (m_nBufferWritePos+nSize, m_nBufferSize+BUFFER_CHUNK_GROW); + m_pBuffer = new BYTE[m_nBufferSize]; + if (pPrev != NULL) { + memcpy_s (m_pBuffer, m_nBufferSize, pPrev, m_nBufferWritePos); + SAFE_DELETE (pPrev); + } + } + memcpy_s (m_pBuffer+m_nBufferWritePos, m_nBufferSize, pData, nSize); + m_nBufferWritePos += nSize; + return S_OK; + } + return S_FALSE; +} + +#define MARKER if(gb.BitRead(1) != 1) {ASSERT(0); return(E_FAIL);} + +HRESULT CDVBSub::ParseSample (IMediaSample* pSample) +{ + CheckPointer (pSample, E_POINTER); + HRESULT hr; + BYTE* pData = NULL; + int nSize; + DVB_SEGMENT_TYPE nCurSegment; + + hr = pSample->GetPointer(&pData); + if(FAILED(hr) || pData == NULL) { + return hr; + } + nSize = pSample->GetActualDataLength(); + + if (*((LONG*)pData) == 0xBD010000) { + CGolombBuffer gb (pData, nSize); + + gb.SkipBytes(4); + WORD wLength = (WORD)gb.BitRead(16); + UNUSED_ALWAYS(wLength); + + if (gb.BitRead(2) != 2) { + return E_FAIL; // type + } + + gb.BitRead(2); // scrambling + gb.BitRead(1); // priority + gb.BitRead(1); // alignment + gb.BitRead(1); // copyright + gb.BitRead(1); // original + BYTE fpts = (BYTE)gb.BitRead(1); // fpts + BYTE fdts = (BYTE)gb.BitRead(1); // fdts + gb.BitRead(1); // escr + gb.BitRead(1); // esrate + gb.BitRead(1); // dsmtrickmode + gb.BitRead(1); // morecopyright + gb.BitRead(1); // crc + gb.BitRead(1); // extension + gb.BitRead(8); // hdrlen + + if(fpts) { + BYTE b = (BYTE)gb.BitRead(4); + if(!(fdts && b == 3 || !fdts && b == 2)) { + ASSERT(0); + return(E_FAIL); + } + + REFERENCE_TIME pts = 0; + pts |= gb.BitRead(3) << 30; + MARKER; // 32..30 + pts |= gb.BitRead(15) << 15; + MARKER; // 29..15 + pts |= gb.BitRead(15); + MARKER; // 14..0 + pts = 10000*pts/90; + + m_rtStart = pts; + m_rtStop = pts+1; + } else { + m_rtStart = INVALID_TIME; + m_rtStop = INVALID_TIME; + } + + nSize -= 14; + pData += 14; + pSample->GetTime(&m_rtStart, &m_rtStop); + pSample->GetMediaTime(&m_rtStart, &m_rtStop); + } else if (SUCCEEDED (pSample->GetTime(&m_rtStart, &m_rtStop))) { + pSample->SetTime(&m_rtStart, &m_rtStop); + } + + //FILE* hFile = fopen ("D:\\Sources\\mpc-hc\\A garder\\TestSubRip\\dvbsub.dat", "ab"); + //if(hFile != NULL) + //{ + // //BYTE Buff[5] = {48}; + + // //*((DWORD*)(Buff+1)) = lSampleLen; + // //fwrite (Buff, 1, sizeof(Buff), hFile); + // fwrite (pData, 1, lSampleLen, hFile); + // fclose(hFile); + //} + + if (AddToBuffer (pData, nSize) == S_OK) { + CGolombBuffer gb (m_pBuffer+m_nBufferReadPos, m_nBufferWritePos-m_nBufferReadPos); + int nLastPos = 0; + + while (!gb.IsEOF()) { + if (gb.ReadByte() == 0x0F) { + WORD wPageId; + WORD wSegLength; + + nCurSegment = (DVB_SEGMENT_TYPE) gb.ReadByte(); + wPageId = gb.ReadShort(); + wSegLength = gb.ReadShort(); + + if (gb.RemainingSize() < wSegLength) { + hr = S_FALSE; + break; + } + + switch (nCurSegment) { + case PAGE : { + CAutoPtr pPage; + ParsePage(gb, wSegLength, pPage); + + if (pPage->PageState == DPS_ACQUISITION) { + m_pCurrentPage = pPage; + m_pCurrentPage->rtStart = m_rtStart; + TRACE_DVB ("DVB - Page started %S\n", ReftimeToString(m_rtStart)); + m_rtStart = INVALID_TIME; + } else { + TRACE_DVB ("DVB - Page update\n"); + } + } + break; + case REGION : + ParseRegion(gb, wSegLength); + TRACE_DVB ("DVB - Region\n"); + break; + case CLUT : + ParseClut(gb, wSegLength); + TRACE_DVB ("DVB - Clut \n"); + break; + case OBJECT : + ParseObject(gb, wSegLength); + TRACE_DVB ("DVB - Object\n"); + break; + case DISPLAY : + ParseDisplay(gb, wSegLength); + break; + case END_OF_DISPLAY : + if (m_pCurrentPage != NULL && m_rtStart != INVALID_TIME) { + m_pCurrentPage->rtStop = m_rtStart; + TRACE_DVB ("DVB - End display %S - %S\n", ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); + m_Pages.AddTail (m_pCurrentPage.Detach()); + } + break; + default : + // gb.SkipBytes(wSegLength); + break; + } + nLastPos = gb.GetPos(); + } + } + m_nBufferReadPos += nLastPos; + } + + return hr; +} + +void CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox) +{ + DVB_PAGE* pPage = FindPage (rt); + + if (pPage != NULL) { + pPage->Rendered = true; + for (int i=0; iRegionCount; i++) { + CDVBSub::DVB_REGION* pRegion = &pPage->Regions[i]; + for (int j=0; jObjectCount; j++) { + CompositionObject* pObject = FindObject (pPage, pRegion->Objects[j].object_id); + if (pObject) { + SHORT nX, nY; + nX = pRegion->HorizAddr + pRegion->Objects[j].object_horizontal_position; + nY = pRegion->VertAddr + pRegion->Objects[j].object_vertical_position; + pObject->m_width = pRegion->width; + pObject->m_height = pRegion->height; + pObject->SetPalette(pRegion->Clut.Size, pRegion->Clut.Palette, false); + pObject->RenderDvb(spd, nX, nY); + } + } + } + + bbox.left = 0; + bbox.top = 0; + bbox.right = m_Display.width; + bbox.bottom = m_Display.height; + + } +} + +HRESULT CDVBSub::GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + // TODO : limit size for HDTV + + // Texture size should be video size width. Height is limited (to prevent performances issues with + // more than 1024x768 pixels) + MaxTextureSize.cx = min (m_Display.width, 1920); + MaxTextureSize.cy = min (m_Display.height, 1024*768/MaxTextureSize.cx); + + VideoSize.cx = m_Display.width; + VideoSize.cy = m_Display.height; + + VideoTopLeft.x = 0; + VideoTopLeft.y = 0; + + return S_OK; +} + +POSITION CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + DVB_PAGE* pPage; + + // Cleanup old PG + while (m_Pages.GetCount()>0) { + pPage = m_Pages.GetHead(); + if (pPage->rtStop < rt) { + if (!pPage->Rendered) { + TRACE_DVB ("DVB - remove unrendered object, %S - %S\n", ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); + } + + //TRACE_HDMVSUB ("CHdmvSub:HDMV remove object %d %S => %S (rt=%S)\n", pPage->GetRLEDataSize(), + // ReftimeToString (pPage->rtStart), ReftimeToString(pPage->rtStop), ReftimeToString(rt)); + m_Pages.RemoveHead(); + delete pPage; + } else { + break; + } + } + + return m_Pages.GetHeadPosition(); +} + +POSITION CDVBSub::GetNext(POSITION pos) +{ + m_Pages.GetNext(pos); + return pos; +} + + +REFERENCE_TIME CDVBSub::GetStart(POSITION nPos) +{ + DVB_PAGE* pPage = m_Pages.GetAt(nPos); + return pPage!=NULL ? pPage->rtStart : INVALID_TIME; +} + +REFERENCE_TIME CDVBSub::GetStop(POSITION nPos) +{ + DVB_PAGE* pPage = m_Pages.GetAt(nPos); + return pPage!=NULL ? pPage->rtStop : INVALID_TIME; +} + + +void CDVBSub::Reset() +{ + m_nBufferReadPos = 0; + m_nBufferWritePos = 0; + m_pCurrentPage.Free(); + + DVB_PAGE* pPage; + while (m_Pages.GetCount() > 0) { + pPage = m_Pages.RemoveHead(); + delete pPage; + } + +} + +HRESULT CDVBSub::ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage) +{ + WORD wEnd = (WORD)gb.GetPos() + wSegLength; + int nPos = 0; + + pPage.Attach (DNew DVB_PAGE()); + pPage->PageTimeOut = gb.ReadByte(); + pPage->PageVersionNumber = (BYTE)gb.BitRead(4); + pPage->PageState = (BYTE)gb.BitRead(2); + pPage->RegionCount = 0; + gb.BitRead(2); // Reserved + while (gb.GetPos() < wEnd) { + if (nPos < MAX_REGIONS) { + pPage->Regions[nPos].Id = gb.ReadByte(); + gb.ReadByte(); // Reserved + pPage->Regions[nPos].HorizAddr = gb.ReadShort(); + pPage->Regions[nPos].VertAddr = gb.ReadShort(); + pPage->RegionCount++; + } + nPos++; + } + + return S_OK; +} + +HRESULT CDVBSub::ParseDisplay(CGolombBuffer& gb, WORD wSegLength) +{ + m_Display.version_number = (BYTE)gb.BitRead (4); + m_Display.display_window_flag = (BYTE)gb.BitRead (1); + gb.BitRead(3); // reserved + m_Display.width = gb.ReadShort(); + m_Display.height = gb.ReadShort(); + if (m_Display.display_window_flag) { + m_Display.horizontal_position_minimun = gb.ReadShort(); + m_Display.horizontal_position_maximum = gb.ReadShort(); + m_Display.vertical_position_minimun = gb.ReadShort(); + m_Display.vertical_position_maximum = gb.ReadShort(); + } + + return S_OK; +} + +HRESULT CDVBSub::ParseRegion(CGolombBuffer& gb, WORD wSegLength) +{ + WORD wEnd = (WORD)gb.GetPos() + wSegLength; + CDVBSub::DVB_REGION* pRegion; + CDVBSub::DVB_REGION DummyRegion; + + pRegion = FindRegion (m_pCurrentPage, gb.ReadByte()); + + if (pRegion == NULL) { + pRegion = &DummyRegion; + } + + if (pRegion != NULL) { + pRegion->version_number = (BYTE)gb.BitRead(4); + pRegion->fill_flag = (BYTE)gb.BitRead(1); + gb.BitRead(3); // Reserved + pRegion->width = gb.ReadShort(); + pRegion->height = gb.ReadShort(); + pRegion->level_of_compatibility = (BYTE)gb.BitRead(3); + pRegion->depth = (BYTE)gb.BitRead(3); + gb.BitRead(2); // Reserved + pRegion->CLUT_id = gb.ReadByte(); + pRegion->_8_bit_pixel_code = gb.ReadByte(); + pRegion->_4_bit_pixel_code = (BYTE)gb.BitRead(4); + pRegion->_2_bit_pixel_code = (BYTE)gb.BitRead(2); + gb.BitRead(2); // Reserved + + pRegion->ObjectCount = 0; + while (gb.GetPos() < wEnd) { + DVB_OBJECT* pObject = &pRegion->Objects[pRegion->ObjectCount]; + pObject->object_id = gb.ReadShort(); + pObject->object_type = (BYTE)gb.BitRead(2); + pObject->object_provider_flag = (BYTE)gb.BitRead(2); + pObject->object_horizontal_position = (SHORT)gb.BitRead(12); + gb.BitRead(4); // Reserved + pObject->object_vertical_position = (SHORT)gb.BitRead(12); + if (pObject->object_type == 0x01 || pObject->object_type == 0x02) { + pObject->foreground_pixel_code = gb.ReadByte(); + pObject->background_pixel_code = gb.ReadByte(); + } + pRegion->ObjectCount++; + } + } else { + gb.SkipBytes (wSegLength-1); + } + + return S_OK; +} + +HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = S_OK; + WORD wEnd = (WORD)gb.GetPos() + wSegLength; + CDVBSub::DVB_CLUT* pClut; + + pClut = FindClut (m_pCurrentPage, gb.ReadByte()); + // ASSERT (pClut != NULL); + if (pClut != NULL) { + pClut->version_number = (BYTE)gb.BitRead(4); + gb.BitRead(4); // Reserved + + pClut->Size = 0; + while (gb.GetPos() < wEnd) { + BYTE entry_id = gb.ReadByte()+1; + BYTE _2_bit = (BYTE)gb.BitRead(1); + BYTE _4_bit = (BYTE)gb.BitRead(1); + BYTE _8_bit = (BYTE)gb.BitRead(1); + UNUSED_ALWAYS(_2_bit); + UNUSED_ALWAYS(_4_bit); + UNUSED_ALWAYS(_8_bit); + gb.BitRead(4); // Reserved + + pClut->Palette[entry_id].entry_id = entry_id; + if (gb.BitRead(1)) { + pClut->Palette[entry_id].Y = gb.ReadByte(); + pClut->Palette[entry_id].Cr = gb.ReadByte(); + pClut->Palette[entry_id].Cb = gb.ReadByte(); + pClut->Palette[entry_id].T = 255-gb.ReadByte(); + } else { + pClut->Palette[entry_id].Y = (BYTE)gb.BitRead(6)<<2; + pClut->Palette[entry_id].Cr = (BYTE)gb.BitRead(4)<<4; + pClut->Palette[entry_id].Cb = (BYTE)gb.BitRead(4)<<4; + pClut->Palette[entry_id].T = 255-((BYTE)gb.BitRead(2)<<6); + } + pClut->Size = max (pClut->Size, entry_id); + } + } + + return hr; +} + +HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_FAIL; + + if (m_pCurrentPage && wSegLength > 2) { + CompositionObject* pObject = DNew CompositionObject(); + BYTE object_coding_method; + + pObject->m_object_id_ref = gb.ReadShort(); + pObject->m_version_number = (BYTE)gb.BitRead(4); + + object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method + gb.BitRead(1); // non_modifying_colour_flag + gb.BitRead(1); // reserved + + if (object_coding_method == 0x00) { + pObject->SetRLEData (gb.GetBufferPos(), wSegLength-3, wSegLength-3); + gb.SkipBytes(wSegLength-3); + m_pCurrentPage->Objects.AddTail (pObject); + hr = S_OK; + } else { + delete pObject; + hr = E_NOTIMPL; + } + } + + + return hr; +} diff --git a/src/subtitles/DVBSub.h b/src/subtitles/DVBSub.h new file mode 100644 index 0000000..3548c2a --- /dev/null +++ b/src/subtitles/DVBSub.h @@ -0,0 +1,214 @@ +/* + * $Id: DVBSub.h 2786 2010-12-17 16:42:55Z XhmikosR $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#pragma once + +#include "BaseSub.h" + +#define MAX_REGIONS 10 +#define MAX_OBJECTS 10 // Max number of objects per region + +class CGolombBuffer; + +class CDVBSub : public CBaseSub +{ +public: + CDVBSub(void); + ~CDVBSub(void); + + virtual HRESULT ParseSample (IMediaSample* pSample); + virtual void Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox); + virtual HRESULT GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft); + virtual POSITION GetStartPosition(REFERENCE_TIME rt, double fps); + virtual POSITION GetNext(POSITION pos); + virtual REFERENCE_TIME GetStart(POSITION nPos); + virtual REFERENCE_TIME GetStop(POSITION nPos); + virtual void Reset(); + + // EN 300-743, table 2 + enum DVB_SEGMENT_TYPE { + NO_SEGMENT = 0xFFFF, + PAGE = 0x10, + REGION = 0x11, + CLUT = 0x12, + OBJECT = 0x13, + DISPLAY = 0x14, + END_OF_DISPLAY = 0x80 + }; + + // EN 300-743, table 6 + enum DVB_OBJECT_TYPE { + OT_BASIC_BITMAP = 0x00, + OT_BASIC_CHAR = 0x01, + OT_COMPOSITE_STRING = 0x02 + }; + + enum DVB_PAGE_STATE { + DPS_NORMAL = 0x00, + DPS_ACQUISITION = 0x01, + DPS_MODE = 0x02, + DPS_RESERVED = 0x03 + }; + + struct DVB_CLUT { + BYTE id; + BYTE version_number; + BYTE Size; + + HDMV_PALETTE Palette[256]; + + DVB_CLUT() { + memset (Palette, 0, sizeof(Palette)); + } + }; + + struct DVB_DISPLAY { + BYTE version_number; + BYTE display_window_flag; + SHORT width; + SHORT height; + SHORT horizontal_position_minimun; + SHORT horizontal_position_maximum; + SHORT vertical_position_minimun; + SHORT vertical_position_maximum; + + DVB_DISPLAY() { + // Default value (�5.1.3) + version_number = 0; + width = 720; + height = 576; + } + }; + + struct DVB_OBJECT { + SHORT object_id; + BYTE object_type; + BYTE object_provider_flag; + SHORT object_horizontal_position; + SHORT object_vertical_position; + BYTE foreground_pixel_code; + BYTE background_pixel_code; + + DVB_OBJECT() { + object_id = 0xFF; + object_type = 0; + object_provider_flag = 0; + object_horizontal_position = 0; + object_vertical_position = 0; + foreground_pixel_code = 0; + background_pixel_code = 0; + } + }; + + struct DVB_REGION { + BYTE Id; + WORD HorizAddr; + WORD VertAddr; + BYTE version_number; + BYTE fill_flag; + WORD width; + WORD height; + BYTE level_of_compatibility; + BYTE depth; + BYTE CLUT_id; + BYTE _8_bit_pixel_code; + BYTE _4_bit_pixel_code; + BYTE _2_bit_pixel_code; + int ObjectCount; + DVB_OBJECT Objects[MAX_OBJECTS]; + + DVB_CLUT Clut; + + DVB_REGION() { + Id = 0; + HorizAddr = 0; + VertAddr = 0; + version_number = 0; + fill_flag = 0; + width = 0; + height = 0; + level_of_compatibility = 0; + depth = 0; + CLUT_id = 0; + _8_bit_pixel_code = 0; + _4_bit_pixel_code = 0; + _2_bit_pixel_code = 0; + } + }; + + class DVB_PAGE + { + public : + REFERENCE_TIME rtStart; + REFERENCE_TIME rtStop; + BYTE PageTimeOut; + BYTE PageVersionNumber; + BYTE PageState; + int RegionCount; + DVB_REGION Regions[MAX_REGIONS]; + CAtlList Objects; + bool Rendered; + + DVB_PAGE() { + PageTimeOut = 0; + PageVersionNumber = 0; + PageState = 0; + RegionCount = 0; + Rendered = false; + } + + ~DVB_PAGE() { + CompositionObject* pPage; + while (Objects.GetCount() > 0) { + pPage = Objects.RemoveHead(); + delete pPage; + } + } + }; + +private: + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + + int m_nBufferSize; + int m_nBufferReadPos; + int m_nBufferWritePos; + BYTE* m_pBuffer; + CAtlList m_Pages; + CAutoPtr m_pCurrentPage; + DVB_DISPLAY m_Display; + REFERENCE_TIME m_rtStart; + REFERENCE_TIME m_rtStop; + + HRESULT AddToBuffer(BYTE* pData, int nSize); + DVB_PAGE* FindPage(REFERENCE_TIME rt); + DVB_REGION* FindRegion(DVB_PAGE* pPage, BYTE bRegionId); + DVB_CLUT* FindClut(DVB_PAGE* pPage, BYTE bClutId); + CompositionObject* FindObject(DVB_PAGE* pPage, SHORT sObjectId); + + HRESULT ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage); + HRESULT ParseDisplay(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseRegion(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseClut(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseObject(CGolombBuffer& gb, WORD wSegLength); + +}; diff --git a/src/subtitles/GFN.cpp b/src/subtitles/GFN.cpp index 2fbcad7..5773212 100644 --- a/src/subtitles/GFN.cpp +++ b/src/subtitles/GFN.cpp @@ -28,7 +28,7 @@ TCHAR* exttypestr[] = { _T("srt"), _T("sub"), _T("smi"), _T("psb"), _T("ssa"), _T("ass"), _T("idx"), _T("usf"), - _T("xss"), _T("txt"), _T("ssf"), _T("rt") + _T("xss"), _T("txt"), _T("ssf"), _T("rt"), _T("sup") }; static TCHAR* ext[2][countof(exttypestr)] = @@ -36,12 +36,12 @@ static TCHAR* ext[2][countof(exttypestr)] = { _T(".srt"), _T(".sub"), _T(".smi"), _T(".psb"), _T(".ssa"), _T(".ass"), _T(".idx"), _T(".usf"), - _T(".xss"), _T(".txt"), _T(".ssf"), _T(".rt") + _T(".xss"), _T(".txt"), _T(".ssf"), _T(".rt"), _T(".sup") }, { _T(".*.srt"), _T(".*.sub"), _T(".*.smi"), _T(".*.psb"), _T(".*.ssa"), _T(".*.ass"), _T(".*.dummyidx"), _T(".*.usf"), - _T(".*.xss"), _T(".*.txt"), _T(".*.ssf"), _T(".*.rt") + _T(".*.xss"), _T(".*.txt"), _T(".*.ssf"), _T(".*.rt"), _T(".*.sup") }, }; diff --git a/src/subtitles/GFN.h b/src/subtitles/GFN.h index b6c03b9..6790124 100644 --- a/src/subtitles/GFN.h +++ b/src/subtitles/GFN.h @@ -23,7 +23,7 @@ #include -enum exttype {EXTSRT = 0, EXTSUB, EXTSMI, EXTPSB, EXTSSA, EXTASS, EXTIDX, EXTUSF, EXTXSS}; +enum exttype {EXTSRT = 0, EXTSUB, EXTSMI, EXTPSB, EXTSSA, EXTASS, EXTIDX, EXTUSF, EXTXSS, EXTRT}; extern TCHAR* exttypestr[]; typedef struct {CString fn; /*exttype ext;*/} SubFile; extern void GetSubFileNames(CString fn, CAtlArray& paths, CAtlArray& ret); diff --git a/src/subtitles/HdmvSub.cpp b/src/subtitles/HdmvSub.cpp new file mode 100644 index 0000000..7c246c4 --- /dev/null +++ b/src/subtitles/HdmvSub.cpp @@ -0,0 +1,375 @@ +/* + * $Id: HdmvSub.cpp 3720 2011-09-12 00:30:00Z aleksoid $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "stdafx.h" +#include "HdmvSub.h" +#include "../DSUtil/GolombBuffer.h" + +#if (0) // Set to 1 to activate HDMV subtitles traces + #define TRACE_HDMVSUB TRACE +#else + #define TRACE_HDMVSUB +#endif + + +CHdmvSub::CHdmvSub(void) + : CBaseSub(ST_HDMV) +{ + m_nColorNumber = 0; + + m_nCurSegment = NO_SEGMENT; + m_pSegBuffer = NULL; + m_nTotalSegBuffer = 0; + m_nSegBufferPos = 0; + m_nSegSize = 0; + m_pCurrentObject = NULL; + m_pDefaultPalette = NULL; + m_nDefaultPaletteNbEntry = 0; + + memset (&m_VideoDescriptor, 0, sizeof(VIDEO_DESCRIPTOR)); +} + +CHdmvSub::~CHdmvSub() +{ + Reset(); + + delete[] m_pSegBuffer; + delete[] m_pDefaultPalette; + delete m_pCurrentObject; +} + + +void CHdmvSub::AllocSegment(int nSize) +{ + if (nSize > m_nTotalSegBuffer) { + delete[] m_pSegBuffer; + m_pSegBuffer = DNew BYTE[nSize]; + m_nTotalSegBuffer = nSize; + } + m_nSegBufferPos = 0; + m_nSegSize = nSize; +} + +POSITION CHdmvSub::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CompositionObject* pObject; + + // Cleanup old PG + while (m_pObjects.GetCount()>0) { + pObject = m_pObjects.GetHead(); + if (pObject->m_rtStop < rt) { + TRACE_HDMVSUB ("CHdmvSub:HDMV remove object %d %S => %S (rt=%S)\n", pObject->GetRLEDataSize(), + ReftimeToString (pObject->m_rtStart), ReftimeToString(pObject->m_rtStop), ReftimeToString(rt)); + m_pObjects.RemoveHead(); + delete pObject; + } else { + break; + } + } + + return m_pObjects.GetHeadPosition(); +} + +HRESULT CHdmvSub::ParseSample(IMediaSample* pSample) +{ + CheckPointer (pSample, E_POINTER); + HRESULT hr; + REFERENCE_TIME rtStart = INVALID_TIME, rtStop = INVALID_TIME; + BYTE* pData = NULL; + int lSampleLen; + + hr = pSample->GetPointer(&pData); + if(FAILED(hr) || pData == NULL) { + return hr; + } + lSampleLen = pSample->GetActualDataLength(); + + pSample->GetTime(&rtStart, &rtStop); + if (pData) { + CGolombBuffer SampleBuffer (pData, lSampleLen); + + while (!SampleBuffer.IsEOF()) { + if (m_nCurSegment == NO_SEGMENT) { + HDMV_SEGMENT_TYPE nSegType = (HDMV_SEGMENT_TYPE)SampleBuffer.ReadByte(); + USHORT nUnitSize = SampleBuffer.ReadShort(); + lSampleLen -=3; + + switch (nSegType) { + case PALETTE : + case OBJECT : + case PRESENTATION_SEG : + case END_OF_DISPLAY : + m_nCurSegment = nSegType; + AllocSegment (nUnitSize); + break; + + case WINDOW_DEF : + case INTERACTIVE_SEG : + case HDMV_SUB1 : + case HDMV_SUB2 : + // Ignored stuff... + SampleBuffer.SkipBytes(nUnitSize); + break; + default : + return VFW_E_SAMPLE_REJECTED; + } + } + + if (m_nCurSegment != NO_SEGMENT) { + if (m_nSegBufferPos < m_nSegSize) { + int nSize = min (m_nSegSize-m_nSegBufferPos, lSampleLen); + SampleBuffer.ReadBuffer (m_pSegBuffer+m_nSegBufferPos, nSize); + m_nSegBufferPos += nSize; + } + + if (m_nSegBufferPos >= m_nSegSize) { + CGolombBuffer SegmentBuffer (m_pSegBuffer, m_nSegSize); + + switch (m_nCurSegment) { + case PALETTE : + TRACE_HDMVSUB ("CHdmvSub:PALETTE rtStart=%10I64d\n", rtStart); + ParsePalette(&SegmentBuffer, m_nSegSize); + break; + case OBJECT : + TRACE_HDMVSUB ("CHdmvSub:OBJECT %S\n", ReftimeToString(rtStart)); + ParseObject(&SegmentBuffer, m_nSegSize); + break; + case PRESENTATION_SEG : + TRACE_HDMVSUB ("CHdmvSub:PRESENTATION_SEG %S (size=%d)\n", ReftimeToString(rtStart), m_nSegSize); + + if (m_pCurrentObject) { + TRACE_HDMVSUB ("CHdmvSub:PRESENTATION_SEG %d\n", m_pCurrentObject->m_nObjectNumber); + if(m_pCurrentObject->m_nObjectNumber > 1) { + m_pCurrentObject->m_nObjectNumber--; + break; + } + m_pCurrentObject->m_rtStop = rtStart; + m_pObjects.AddTail (m_pCurrentObject); + TRACE_HDMVSUB ("CHdmvSub:HDMV : %S => %S\n", ReftimeToString (m_pCurrentObject->m_rtStart), ReftimeToString(rtStart)); + m_pCurrentObject = NULL; + } + + if (ParsePresentationSegment(&SegmentBuffer) > 0) { + m_pCurrentObject->m_rtStart = rtStart; + m_pCurrentObject->m_rtStop = _I64_MAX; + } + break; + case WINDOW_DEF : + // TRACE_HDMVSUB ("CHdmvSub:WINDOW_DEF %S\n", ReftimeToString(rtStart)); + break; + case END_OF_DISPLAY : + // TRACE_HDMVSUB ("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToString(rtStart)); + break; + default : + TRACE_HDMVSUB ("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n", m_nCurSegment, rtStart); + } + + m_nCurSegment = NO_SEGMENT; + } + } + } + } + + return hr; +} + +int CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer) +{ + COMPOSITION_DESCRIPTOR CompositionDescriptor; + BYTE nObjectNumber; + //bool palette_update_flag; + //BYTE palette_id_ref; + + ParseVideoDescriptor(pGBuffer, &m_VideoDescriptor); + ParseCompositionDescriptor(pGBuffer, &CompositionDescriptor); + pGBuffer->ReadByte(); //palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); + pGBuffer->ReadByte(); //palette_id_ref = pGBuffer->ReadByte(); + nObjectNumber = pGBuffer->ReadByte(); + + TRACE_HDMVSUB( "CHdmvSub::ParsePresentationSegment Size = %d, nObjectNumber = %d\n", pGBuffer->GetSize(), nObjectNumber); + + if (nObjectNumber > 0) { + delete m_pCurrentObject; + m_pCurrentObject = DNew CompositionObject(); + m_pCurrentObject->m_nObjectNumber = nObjectNumber; + for(int i=0; iReadByte(); + BYTE palette_version_number = pGBuffer->ReadByte(); + UNUSED_ALWAYS(palette_id); + UNUSED_ALWAYS(palette_version_number); + + ASSERT ((nSize-2) % sizeof(HDMV_PALETTE) == 0); + nNbEntry = (nSize-2) / sizeof(HDMV_PALETTE); + HDMV_PALETTE* pPalette = (HDMV_PALETTE*)pGBuffer->GetBufferPos(); + + if (m_pDefaultPalette == NULL || m_nDefaultPaletteNbEntry != nNbEntry) { + delete[] m_pDefaultPalette; + m_pDefaultPalette = new HDMV_PALETTE[nNbEntry]; + m_nDefaultPaletteNbEntry = nNbEntry; + } + memcpy (m_pDefaultPalette, pPalette, nNbEntry*sizeof(HDMV_PALETTE)); + + if (m_pCurrentObject) { + m_pCurrentObject->SetPalette (nNbEntry, pPalette, m_VideoDescriptor.nVideoWidth>720); + } +} + +void CHdmvSub::ParseObject(CGolombBuffer* pGBuffer, USHORT nUnitSize) // #498 +{ + SHORT object_id = pGBuffer->ReadShort(); + UNUSED_ALWAYS(object_id); + BYTE m_sequence_desc; + + ASSERT (m_pCurrentObject != NULL); + if (m_pCurrentObject) { // && m_pCurrentObject->m_object_id_ref == object_id) + m_pCurrentObject->m_version_number = pGBuffer->ReadByte(); + m_sequence_desc = pGBuffer->ReadByte(); + + if (m_sequence_desc & 0x80) { + DWORD object_data_length = (DWORD)pGBuffer->BitRead(24); + + m_pCurrentObject->m_width = pGBuffer->ReadShort(); + m_pCurrentObject->m_height = pGBuffer->ReadShort(); + + m_pCurrentObject->SetRLEData (pGBuffer->GetBufferPos(), nUnitSize-11, object_data_length-4); + + TRACE_HDMVSUB ("CHdmvSub:NewObject size=%ld, total obj=%d, %dx%d\n", object_data_length, m_pObjects.GetCount(), + m_pCurrentObject->m_width, m_pCurrentObject->m_height); + } else { + m_pCurrentObject->AppendRLEData (pGBuffer->GetBufferPos(), nUnitSize-4); + } + } +} + +void CHdmvSub::ParseCompositionObject(CGolombBuffer* pGBuffer, CompositionObject* pCompositionObject) +{ + BYTE bTemp; + pCompositionObject->m_object_id_ref = pGBuffer->ReadShort(); + pCompositionObject->m_window_id_ref = pGBuffer->ReadByte(); + bTemp = pGBuffer->ReadByte(); + pCompositionObject->m_object_cropped_flag = !!(bTemp & 0x80); + pCompositionObject->m_forced_on_flag = !!(bTemp & 0x40); + pCompositionObject->m_horizontal_position = pGBuffer->ReadShort(); + pCompositionObject->m_vertical_position = pGBuffer->ReadShort(); + + if (pCompositionObject->m_object_cropped_flag) { + pCompositionObject->m_cropping_horizontal_position = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_vertical_position = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_width = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_height = pGBuffer->ReadShort(); + } +} + +void CHdmvSub::ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor) +{ + pVideoDescriptor->nVideoWidth = pGBuffer->ReadShort(); + pVideoDescriptor->nVideoHeight = pGBuffer->ReadShort(); + pVideoDescriptor->bFrameRate = pGBuffer->ReadByte(); +} + +void CHdmvSub::ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor) +{ + pCompositionDescriptor->nNumber = pGBuffer->ReadShort(); + pCompositionDescriptor->bState = pGBuffer->ReadByte(); +} + +void CHdmvSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox) +{ + CompositionObject* pObject = FindObject (rt); + + ASSERT (pObject!=NULL && spd.w >= (pObject->m_horizontal_position + pObject->m_width) && spd.h >= (pObject->m_vertical_position + pObject->m_height)); + + if (pObject && pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 && + spd.w >= (pObject->m_horizontal_position + pObject->m_width) && + spd.h >= (pObject->m_vertical_position + pObject->m_height)) { + if (!pObject->HavePalette()) { + pObject->SetPalette (m_nDefaultPaletteNbEntry, m_pDefaultPalette, m_VideoDescriptor.nVideoWidth>720); + } + + TRACE_HDMVSUB ("CHdmvSub:Render size=%ld, ObjRes=%dx%d, SPDRes=%dx%d\n", pObject->GetRLEDataSize(), + pObject->m_width, pObject->m_height, spd.w, spd.h); + pObject->RenderHdmv(spd); + + bbox.left = pObject->m_horizontal_position; + bbox.top = pObject->m_vertical_position; + bbox.right = bbox.left + pObject->m_width; + bbox.bottom = bbox.top + pObject->m_height; + } +} + +HRESULT CHdmvSub::GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + CompositionObject* pObject = m_pObjects.GetAt (pos); + if (pObject) { + MaxTextureSize.cx = m_VideoDescriptor.nVideoWidth; + MaxTextureSize.cy = m_VideoDescriptor.nVideoHeight; + + VideoSize.cx = m_VideoDescriptor.nVideoWidth; + VideoSize.cy = m_VideoDescriptor.nVideoHeight; + + // The subs will be directly rendered into the proper position! + VideoTopLeft.x = 0; //pObject->m_horizontal_position; + VideoTopLeft.y = 0; //pObject->m_vertical_position; + + return S_OK; + } + + ASSERT (FALSE); + return E_INVALIDARG; +} + + +void CHdmvSub::Reset() +{ + CompositionObject* pObject; + while (m_pObjects.GetCount() > 0) { + pObject = m_pObjects.RemoveHead(); + delete pObject; + } +} + +CompositionObject* CHdmvSub::FindObject(REFERENCE_TIME rt) +{ + POSITION pos = m_pObjects.GetHeadPosition(); + + while (pos) { + CompositionObject* pObject = m_pObjects.GetAt (pos); + + if (rt >= pObject->m_rtStart && rt < pObject->m_rtStop) { + return pObject; + } + + m_pObjects.GetNext(pos); + } + + return NULL; +} diff --git a/src/subtitles/HdmvSub.h b/src/subtitles/HdmvSub.h new file mode 100644 index 0000000..858eadf --- /dev/null +++ b/src/subtitles/HdmvSub.h @@ -0,0 +1,121 @@ +/* + * $Id: HdmvSub.h 2786 2010-12-17 16:42:55Z XhmikosR $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +#include "BaseSub.h" + +class CGolombBuffer; + +class CHdmvSub : public CBaseSub +{ +public: + + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + + enum HDMV_SEGMENT_TYPE { + NO_SEGMENT = 0xFFFF, + PALETTE = 0x14, + OBJECT = 0x15, + PRESENTATION_SEG = 0x16, + WINDOW_DEF = 0x17, + INTERACTIVE_SEG = 0x18, + END_OF_DISPLAY = 0x80, + HDMV_SUB1 = 0x81, + HDMV_SUB2 = 0x82 + }; + + + struct VIDEO_DESCRIPTOR { + SHORT nVideoWidth; + SHORT nVideoHeight; + BYTE bFrameRate; // <= Frame rate here! + }; + + struct COMPOSITION_DESCRIPTOR { + SHORT nNumber; + BYTE bState; + }; + + struct SEQUENCE_DESCRIPTOR { + BYTE bFirstIn : 1; + BYTE bLastIn : 1; + BYTE bReserved : 8; + }; + + CHdmvSub(); + ~CHdmvSub(); + + HRESULT ParseSample (IMediaSample* pSample); + + + POSITION GetStartPosition(REFERENCE_TIME rt, double fps); + POSITION GetNext(POSITION pos) { + m_pObjects.GetNext(pos); + return pos; + }; + + + virtual REFERENCE_TIME GetStart(POSITION nPos) { + CompositionObject* pObject = m_pObjects.GetAt(nPos); + return pObject!=NULL ? pObject->m_rtStart : INVALID_TIME; + }; + virtual REFERENCE_TIME GetStop(POSITION nPos) { + CompositionObject* pObject = m_pObjects.GetAt(nPos); + return pObject!=NULL ? pObject->m_rtStop : INVALID_TIME; + }; + + void Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox); + HRESULT GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft); + void Reset(); + +private : + + HDMV_SEGMENT_TYPE m_nCurSegment; + BYTE* m_pSegBuffer; + int m_nTotalSegBuffer; + int m_nSegBufferPos; + int m_nSegSize; + + VIDEO_DESCRIPTOR m_VideoDescriptor; + + CompositionObject* m_pCurrentObject; + CAtlList m_pObjects; + + HDMV_PALETTE* m_pDefaultPalette; + int m_nDefaultPaletteNbEntry; + + int m_nColorNumber; + + + int ParsePresentationSegment(CGolombBuffer* pGBuffer); + void ParsePalette(CGolombBuffer* pGBuffer, USHORT nSize); + void ParseObject(CGolombBuffer* pGBuffer, USHORT nUnitSize); + + void ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor); + void ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor); + void ParseCompositionObject(CGolombBuffer* pGBuffer, CompositionObject* pCompositionObject); + + void AllocSegment(int nSize); + + CompositionObject* FindObject(REFERENCE_TIME rt); +}; diff --git a/src/subtitles/Rasterizer.cpp b/src/subtitles/Rasterizer.cpp index e50598c..60a3890 100644 --- a/src/subtitles/Rasterizer.cpp +++ b/src/subtitles/Rasterizer.cpp @@ -2257,4 +2257,25 @@ void ScanLineData::DeleteOutlines() { mWideOutline.clear(); mOutline.clear(); -} \ No newline at end of file +} + +void Rasterizer::FillSolidRect(SubPicDesc& spd, int x, int y, int nWidth, int nHeight, DWORD lColor) +{ + bool fSSE2 = !!(g_cpuid.m_flags & CCpuID::sse2); + + if(fSSE2) { + for (int wy=y; wy>24); + } + } + } else { + for (int wy=y; wy. + * + */ + + +#include "stdafx.h" +#include "HdmvSub.h" +#include "DVBSub.h" +#include "RenderedHdmvSubtitle.h" + +CRenderedHdmvSubtitle::CRenderedHdmvSubtitle(CCritSec* pLock, SUBTITLE_TYPE nType, const CString& name, LCID lcid) + : CSubPicProviderImpl(pLock), m_name(name), m_lcid(lcid) +{ + switch (nType) { + case ST_DVB : + m_pSub = DNew CDVBSub(); + if (name.IsEmpty() || (name == _T("Unknown"))) m_name = "DVB Embedded Subtitle"; + break; + case ST_HDMV : + m_pSub = DNew CHdmvSub(); + if (name.IsEmpty() || (name == _T("Unknown"))) m_name = "HDMV Embedded Subtitle"; + break; + default : + ASSERT (FALSE); + m_pSub = NULL; + } + m_rtStart = 0; +} + +CRenderedHdmvSubtitle::~CRenderedHdmvSubtitle(void) +{ + delete m_pSub; +} + + +STDMETHODIMP CRenderedHdmvSubtitle::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = NULL; + + return + QI(IPersist) + QI(ISubStream) + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CRenderedHdmvSubtitle::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + return m_pSub->GetStartPosition(rt - m_rtStart, fps); +} + +STDMETHODIMP_(POSITION) CRenderedHdmvSubtitle::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csCritSec); + return m_pSub->GetNext (pos); +} + +STDMETHODIMP_(REFERENCE_TIME) CRenderedHdmvSubtitle::GetStart(POSITION pos, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + return m_pSub->GetStart(pos) + m_rtStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CRenderedHdmvSubtitle::GetStop(POSITION pos, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + return m_pSub->GetStop(pos) + m_rtStart; +} + +STDMETHODIMP_(bool) CRenderedHdmvSubtitle::IsAnimated(POSITION pos) +{ + return false; +} + +STDMETHODIMP CRenderedHdmvSubtitle::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + CAutoLock cAutoLock(&m_csCritSec); + m_pSub->Render (spd, rt - m_rtStart, bbox); + + return S_OK; +} + +STDMETHODIMP CRenderedHdmvSubtitle::GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + CAutoLock cAutoLock(&m_csCritSec); + HRESULT hr = m_pSub->GetTextureSize(pos, MaxTextureSize, VideoSize, VideoTopLeft); + return hr; +}; + +// IPersist + +STDMETHODIMP CRenderedHdmvSubtitle::GetClassID(CLSID* pClassID) +{ + return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; +} + +// ISubStream + +STDMETHODIMP_(int) CRenderedHdmvSubtitle::GetStreamCount() +{ + return (1); +} + +STDMETHODIMP CRenderedHdmvSubtitle::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID) +{ + if(iStream != 0) { + return E_INVALIDARG; + } + + if(ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength()+1)*sizeof(WCHAR)); + if(!(*ppName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s (*ppName, m_name.GetLength()+1, CStringW(m_name)); + } + + if(pLCID) { + *pLCID = m_lcid; + } + + return S_OK; +} + +STDMETHODIMP_(int) CRenderedHdmvSubtitle::GetStream() +{ + return(0); +} + +STDMETHODIMP CRenderedHdmvSubtitle::SetStream(int iStream) +{ + return iStream == 0 ? S_OK : E_FAIL; +} + +STDMETHODIMP CRenderedHdmvSubtitle::Reload() +{ + return S_OK; +} + +HRESULT CRenderedHdmvSubtitle::ParseSample (IMediaSample* pSample) +{ + CAutoLock cAutoLock(&m_csCritSec); + HRESULT hr; + + hr = m_pSub->ParseSample (pSample); + return hr; +} + +HRESULT CRenderedHdmvSubtitle::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csCritSec); + + m_pSub->Reset(); + m_rtStart = tStart; + return S_OK; +} diff --git a/src/subtitles/RenderedHdmvSubtitle.h b/src/subtitles/RenderedHdmvSubtitle.h new file mode 100644 index 0000000..78106e2 --- /dev/null +++ b/src/subtitles/RenderedHdmvSubtitle.h @@ -0,0 +1,71 @@ +/* + * $Id: RenderedHdmvSubtitle.h 2804 2010-12-28 13:48:24Z aleksoid $ + * + * (C) 2006-2010 see AUTHORS + * + * This file is part of mplayerc. + * + * Mplayerc is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Mplayerc 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#pragma once + +#include "Rasterizer.h" +#include "../SubPic/SubPicProviderImpl.h" +#include "HdmvSub.h" +#include "BaseSub.h" + + +class __declspec(uuid("FCA68599-C83E-4ea5-94A3-C2E1B0E326B9")) + CRenderedHdmvSubtitle : public CSubPicProviderImpl, public ISubStream +{ +public: + CRenderedHdmvSubtitle(CCritSec* pLock, SUBTITLE_TYPE nType, const CString& name, LCID lcid); + ~CRenderedHdmvSubtitle(void); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetTextureSize (POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload(); + + HRESULT ParseSample (IMediaSample* pSample); + HRESULT NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + +private : + CString m_name; + LCID m_lcid; + REFERENCE_TIME m_rtStart; + + CBaseSub* m_pSub; + CCritSec m_csCritSec; +}; diff --git a/src/subtitles/STS.h b/src/subtitles/STS.h index 6c0c2f5..446df15 100644 --- a/src/subtitles/STS.h +++ b/src/subtitles/STS.h @@ -152,6 +152,7 @@ protected: public: CString m_name; + LCID m_lcid; tmode m_mode; CTextFile::enc m_encoding; CString m_path; diff --git a/src/subtitles/SubtitleInputPin.cpp b/src/subtitles/SubtitleInputPin.cpp index e674494..0eab8fe 100644 --- a/src/subtitles/SubtitleInputPin.cpp +++ b/src/subtitles/SubtitleInputPin.cpp @@ -24,6 +24,7 @@ #include "VobSubFile.h" #include "RTS.h" #include "SSF.h" +#include "RenderedHdmvSubtitle.h" #include #include "..\..\include\moreuuids.h" @@ -62,6 +63,7 @@ HRESULT CSubtitleInputPin::CheckMediaType(const CMediaType* pmt) || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_SSA || pmt->subtype == MEDIASUBTYPE_ASS || pmt->subtype == MEDIASUBTYPE_ASS2) || pmt->majortype == MEDIATYPE_Subtitle && pmt->subtype == MEDIASUBTYPE_SSF || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_VOBSUB) + || IsHdmvSub(pmt) ? S_OK : E_FAIL; } @@ -80,11 +82,26 @@ HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) else if(m_mt.majortype == MEDIATYPE_Subtitle) { SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; - DWORD dwOffset = psi->dwOffset; + DWORD dwOffset = 0; + CString name; + LCID lcid = 0; - CString name = ISO6392ToLanguage(psi->IsoLang); - if(name.IsEmpty()) name = _T("English"); - if(wcslen(psi->TrackName) > 0) name += _T(" (") + CString(psi->TrackName) + _T(")"); + if (psi != NULL) { + dwOffset = psi->dwOffset; + + name = ISO6392ToLanguage(psi->IsoLang); + lcid = ISO6392ToLcid(psi->IsoLang); + + if(wcslen(psi->TrackName) > 0) { + name += (!name.IsEmpty() ? _T(", ") : _T("")) + CString(psi->TrackName); + } + if(name.IsEmpty()) { + name = _T("Unknown"); + } + } + + name.Replace(_T(""), _T(""));//CAUTION: VS may show name.Replace(_T(""),_T("")), however there is a character in the first _T("") + name.Replace(_T(""), _T(""));//CAUTION: VS may show name.Replace(_T(""),_T("")), however there is a character in the first _T("") if(m_mt.subtype == MEDIASUBTYPE_UTF8 /*|| m_mt.subtype == MEDIASUBTYPE_USF*/ @@ -95,6 +112,7 @@ HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) CRenderedTextSubtitle* pRTS = new CRenderedTextSubtitle(m_pSubLock); if(!(m_pSubStream = pRTS)) return E_FAIL; pRTS->m_name = name; + pRTS->m_lcid = lcid; pRTS->m_dstScreenSize = CSize(384, 288); pRTS->CreateDefaultStyle(DEFAULT_CHARSET); @@ -128,6 +146,12 @@ HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) if(!(m_pSubStream = pVSS)) return E_FAIL; pVSS->Open(name, m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset); } + else if (IsHdmvSub(&m_mt)) + { + if(!(m_pSubStream = DNew CRenderedHdmvSubtitle(m_pSubLock, (m_mt.subtype == MEDIASUBTYPE_DVB_SUBTITLES) ? ST_DVB : ST_HDMV, name, lcid))) { + return E_FAIL; + } + } } AddSubStream(m_pSubStream); @@ -192,10 +216,22 @@ STDMETHODIMP CSubtitleInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME CVobSubStream* pVSS = dynamic_cast(static_cast(m_pSubStream)); pVSS->RemoveAll(); } - + else if (IsHdmvSub(&m_mt)) + { + CAutoLock cAutoLock(m_pSubLock); + CRenderedHdmvSubtitle* pHdmvSubtitle = (CRenderedHdmvSubtitle*)(ISubStream*)m_pSubStream; + pHdmvSubtitle->NewSegment (tStart, tStop, dRate); + } return __super::NewSegment(tStart, tStop, dRate); } +interface __declspec(uuid("D3D92BC3-713B-451B-9122-320095D51EA5")) +IMpeg2DemultiplexerTesting : +public IUnknown { + STDMETHOD(GetMpeg2StreamType)(ULONG* plType) = NULL; + STDMETHOD(toto)() = NULL; +}; + STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) { DbgLog(( LOG_TRACE, 4, TEXT(__FUNCTION__) )); @@ -359,6 +395,12 @@ STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) CVobSubStream* pVSS = dynamic_cast(static_cast(m_pSubStream)); pVSS->Add(tStart, tStop, pData, len); } + else if (IsHdmvSub(&m_mt)) + { + CAutoLock cAutoLock(m_pSubLock); + CRenderedHdmvSubtitle* pHdmvSubtitle = (CRenderedHdmvSubtitle*)(ISubStream*)m_pSubStream; + pHdmvSubtitle->ParseSample (pSample); + } } if(fInvalidate) @@ -373,3 +415,11 @@ STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) return hr; } +bool CSubtitleInputPin::IsHdmvSub(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_HDMVSUB || // Blu ray presentation graphics + pmt->subtype == MEDIASUBTYPE_DVB_SUBTITLES || // DVB subtitles + (pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_SubtitleInfo)) // Workaround : support for Haali PGS + ? true + : false; +} \ No newline at end of file diff --git a/src/subtitles/SubtitleInputPin.h b/src/subtitles/SubtitleInputPin.h index fbe6005..6374cd5 100644 --- a/src/subtitles/SubtitleInputPin.h +++ b/src/subtitles/SubtitleInputPin.h @@ -38,6 +38,7 @@ protected: virtual void AddSubStream(ISubStream* pSubStream) = 0; virtual void RemoveSubStream(ISubStream* pSubStream) = 0; virtual void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) = 0; + bool IsHdmvSub(const CMediaType* pmt); public: CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); diff --git a/src/subtitles/subtitles_vs2010.vcxproj b/src/subtitles/subtitles_vs2010.vcxproj index 1a9e338..0f94f41 100644 --- a/src/subtitles/subtitles_vs2010.vcxproj +++ b/src/subtitles/subtitles_vs2010.vcxproj @@ -150,15 +150,20 @@ + + + + AssemblyAndSourceCode AssemblyAndSourceCode AssemblyAndSourceCode + @@ -205,13 +210,18 @@ + + + + + diff --git a/src/subtitles/subtitles_vs2010.vcxproj.filters b/src/subtitles/subtitles_vs2010.vcxproj.filters index 35bc249..18016ab 100644 --- a/src/subtitles/subtitles_vs2010.vcxproj.filters +++ b/src/subtitles/subtitles_vs2010.vcxproj.filters @@ -66,6 +66,21 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -137,5 +152,20 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file -- 2.11.4.GIT