InfoDialog.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #include "../nsavi/nsavi.h"
  2. #include "api__in_avi.h"
  3. #include "../nu/ListView.h"
  4. #include "../nu/AutoWide.h"
  5. #include "resource.h"
  6. #include "main.h"
  7. #include <strsafe.h>
  8. struct KnownField
  9. {
  10. uint32_t field;
  11. wchar_t name[256]; // TODO: change to resource ID
  12. };
  13. static KnownField known_fields[] =
  14. {
  15. {nsaviFOURCC('I','S','F','T'), L"Tool"}, // IDS_FIELD_TOOL
  16. {nsaviFOURCC('I','A','R','T'), L"Artist"}, // IDS_FIELD_ARTIST
  17. {nsaviFOURCC('I','P','U','B'), L"Publisher"}, // IDS_FIELD_PUBLISHER
  18. {nsaviFOURCC('I','A','L','B'), L"Album"}, // IDS_FIELD_ALBUM
  19. {nsaviFOURCC('I','C','O','M'), L"Composer"}, // IDS_FIELD_COMPOSER
  20. {nsaviFOURCC('I','G','N','R'), L"Genre"}, // IDS_FIELD_GENRE
  21. {nsaviFOURCC('I','C','M','T'), L"Comment"}, // IDS_FIELD_COMMENT
  22. {nsaviFOURCC('I','N','A','M'), L"Title"}, // IDS_FIELD_TITLE
  23. {nsaviFOURCC('I','C','O','P'), L"Copyright"}, // IDS_FIELD_COPYRIGHT
  24. };
  25. static KnownField known_video_codecs[] =
  26. {
  27. {nsaviFOURCC('V','P','6','0'), L"On2 VP6"},
  28. {nsaviFOURCC('V','P','6','1'), L"On2 VP6"},
  29. {nsaviFOURCC('V','P','6','2'), L"On2 VP6"},
  30. {nsaviFOURCC('X','V','I','D'), L"MPEG-4 Part 2"},
  31. {nsaviFOURCC('x','v','i','d'), L"MPEG-4 Part 2"},
  32. {nsaviFOURCC('d','i','v','x'), L"MPEG-4 Part 2"},
  33. {nsaviFOURCC('D','I','V','X'), L"MPEG-4 Part 2"},
  34. {nsaviFOURCC('D','X','5','0'), L"MPEG-4 Part 2"},
  35. {nsaviFOURCC('m','p','4','v'), L"MPEG-4 Part 2"},
  36. {nsaviFOURCC('S','E','D','G'), L"MPEG-4 Part 2"},
  37. {nsaviFOURCC('H','2','6','4'), L"H.264"},
  38. {nsaviFOURCC('M','J','P','G'), L"Motion JPEG"},
  39. {nsaviFOURCC('t','s','c','c'), L"TechSmith"},
  40. {nsaviFOURCC('c','v','i','d'), L"Cinepack"},
  41. {nsaviFOURCC('M','P','G','4'), L"MS-MPEG-4 v1"},
  42. {nsaviFOURCC('M','P','4','1'), L"MS-MPEG-4 v1"},
  43. {nsaviFOURCC('M','P','4','2'), L"MS-MPEG-4 v2"},
  44. {nsaviFOURCC('M','P','4','3'), L"MS-MPEG-4 v3"},
  45. {nsavi::video_format_rgb, L"RGB"},
  46. {nsavi::video_format_rle8, L"8bpp RLE"},
  47. {nsavi::video_format_rle4, L"4bpp RLE"},
  48. };
  49. static KnownField known_audio_codecs[] =
  50. {
  51. {nsavi::audio_format_pcm, L"Wave"},
  52. {nsavi::audio_format_ms_adpcm, L"Microsoft ADPCM"},
  53. {nsavi::audio_format_alaw, L"A-law"},
  54. {nsavi::audio_format_ulaw, L"μ-law"},
  55. {nsavi::audio_format_ima_adpcm, L"IMA ADPCM"},
  56. {nsavi::audio_format_truespeech, L"DSP Truespeech"},
  57. {nsavi::audio_format_mp2, L"MPEG Layer 2"},
  58. {nsavi::audio_format_mp3, L"MPEG Layer 3"},
  59. {nsavi::audio_format_a52, L"ATSC A/52 (AC3)"},
  60. {nsavi::audio_format_aac, L"AAC"},
  61. {nsavi::audio_format_vorbis, L"Vorbis"},
  62. {nsavi::audio_format_speex, L"Speex"},
  63. {nsavi::audio_format_extensible, L"Extensible Wave"},
  64. {nsavi::audio_format_dts, L"DTS"},
  65. };
  66. enum
  67. {
  68. COLUMN_TRACK_TYPE = 0,
  69. COLUMN_CODEC_NAME = 1,
  70. COLUMN_CODEC_ID = 2,
  71. COLUMN_DESCRIPTION = 3,
  72. COLUMN_STREAM_NAME = 4,
  73. };
  74. static const wchar_t *FindKnownName(const KnownField *fields, size_t num_fields, uint32_t value)
  75. {
  76. for (size_t i=0;i!=num_fields;i++)
  77. {
  78. if (fields[i].field == value)
  79. {
  80. return fields[i].name;
  81. }
  82. }
  83. return 0;
  84. }
  85. static void MakeStringFromFOURCC(wchar_t *str, uint32_t fourcc)
  86. {
  87. const uint8_t *characters = (const uint8_t *)&(fourcc);
  88. if (fourcc < 65536)
  89. {
  90. StringCchPrintfW(str, 5, L"%X", fourcc);
  91. }
  92. else
  93. {
  94. str[0] = characters[0];
  95. str[1] = characters[1];
  96. str[2] = characters[2];
  97. str[3] = characters[3];
  98. str[4] = 0;
  99. }
  100. }
  101. static INT_PTR CALLBACK InfoDialog_Metadata(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  102. {
  103. switch (uMsg)
  104. {
  105. case WM_INITDIALOG:
  106. {
  107. nsavi::Metadata *metadata = (nsavi::Metadata *)lParam;
  108. SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
  109. W_ListView list_view(hwndDlg, IDC_TRACKLIST);
  110. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_FIELD), 100);
  111. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_FOURCC), 75);
  112. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_VALUE), 250);
  113. nsavi::Info *info;
  114. if (metadata->GetInfo(&info) == nsavi::READ_OK)
  115. {
  116. int n=0;
  117. for (nsavi::Info::const_iterator itr = info->begin();itr!=info->end();itr++)
  118. {
  119. const wchar_t *field_name = FindKnownName(known_fields, sizeof(known_fields)/sizeof(known_fields[0]), itr->first);
  120. wchar_t fourcc[5] = {0};
  121. MakeStringFromFOURCC(fourcc, itr->first);
  122. if (field_name)
  123. n= list_view.AppendItem(field_name, 0);
  124. else
  125. n= list_view.AppendItem(fourcc, 0);
  126. list_view.SetItemText(n, 1, fourcc);
  127. list_view.SetItemText(n, 2, AutoWide(itr->second, CP_ACP/*UTF8*/));
  128. }
  129. }
  130. }
  131. return 1;
  132. case WM_SIZE:
  133. {
  134. RECT r;
  135. GetClientRect(hwndDlg, &r);
  136. SetWindowPos(GetDlgItem(hwndDlg, IDC_TRACKLIST), HWND_TOP, r.left, r.top, r.right, r.bottom, SWP_NOACTIVATE);
  137. }
  138. break;
  139. }
  140. return 0;
  141. }
  142. void GetVideoCodecName(wchar_t *str, size_t str_cch, nsavi::STRF *stream_format)
  143. {
  144. nsavi::video_format *format = (nsavi::video_format *)stream_format;
  145. const wchar_t *codec_name = FindKnownName(known_video_codecs, sizeof(known_video_codecs)/sizeof(known_video_codecs[0]), format->compression);
  146. if (codec_name)
  147. StringCchCopy(str, str_cch, codec_name);
  148. else
  149. MakeStringFromFOURCC(str, format->compression);
  150. }
  151. void GetVideoCodecDescription(wchar_t *str, size_t str_cch, nsavi::STRF *stream_format)
  152. {
  153. nsavi::video_format *format = (nsavi::video_format *)stream_format;
  154. StringCchPrintf(str, str_cch, L"%ux%u", format->width, format->height);
  155. }
  156. void GetAudioCodecName(wchar_t *str, size_t str_cch, nsavi::STRF *stream_format)
  157. {
  158. nsavi::audio_format *format = (nsavi::audio_format *)stream_format;
  159. const wchar_t *codec_name = FindKnownName(known_audio_codecs, sizeof(known_audio_codecs)/sizeof(known_audio_codecs[0]), format->format);
  160. if (codec_name)
  161. StringCchCopy(str, str_cch, codec_name);
  162. else
  163. MakeStringFromFOURCC(str, format->format);
  164. }
  165. void GetAudioCodecDescription(wchar_t *str, size_t str_cch, nsavi::STRF *stream_format)
  166. {
  167. nsavi::audio_format *format = (nsavi::audio_format *)stream_format;
  168. if (format->average_bytes_per_second)
  169. {
  170. StringCchPrintf(str, str_cch, L"%u %s", format->average_bytes_per_second / 125UL, WASABI_API_LNGSTRINGW(IDS_KBPS));
  171. }
  172. else
  173. str[0]=0;
  174. }
  175. static INT_PTR CALLBACK InfoDialog_Tracks(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  176. {
  177. switch (uMsg)
  178. {
  179. case WM_INITDIALOG:
  180. {
  181. nsavi::Metadata *metadata = (nsavi::Metadata *)lParam;
  182. SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
  183. W_ListView list_view(hwndDlg, IDC_TRACKLIST);
  184. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_TRACK_TYPE), 100);
  185. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_CODEC_NAME), 100);
  186. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_CODEC_ID), 75);
  187. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_DESCRIPTION), 100);
  188. list_view.AddCol(WASABI_API_LNGSTRINGW(IDS_COLUMN_STREAM_NAME), 100);
  189. nsavi::HeaderList header_list;
  190. if (metadata->GetHeaderList(&header_list) == nsavi::READ_OK)
  191. {
  192. for (size_t i=0;i!=header_list.stream_list_size;i++)
  193. {
  194. int n;
  195. const nsavi::STRL &stream = header_list.stream_list[i];
  196. switch(stream.stream_header->stream_type)
  197. {
  198. case nsavi::stream_type_audio:
  199. {
  200. n = list_view.AppendItem(WASABI_API_LNGSTRINGW(IDS_TYPE_AUDIO), 0);
  201. nsavi::audio_format *format = (nsavi::audio_format *)stream.stream_format;
  202. wchar_t codec_id[5] = {0};
  203. MakeStringFromFOURCC(codec_id, format->format);
  204. list_view.SetItemText(n, COLUMN_CODEC_ID, codec_id);
  205. const wchar_t *codec_name = FindKnownName(known_audio_codecs, sizeof(known_audio_codecs)/sizeof(known_audio_codecs[0]), format->format);
  206. if (codec_name)
  207. list_view.SetItemText(n, COLUMN_CODEC_NAME, codec_name);
  208. else
  209. list_view.SetItemText(n, COLUMN_CODEC_NAME, codec_id);
  210. wchar_t description[256] = {0};
  211. GetAudioCodecDescription(description, 256, stream.stream_format);
  212. list_view.SetItemText(n, COLUMN_DESCRIPTION, description);
  213. }
  214. break;
  215. case nsavi::stream_type_video:
  216. {
  217. n = list_view.AppendItem(WASABI_API_LNGSTRINGW(IDS_TYPE_VIDEO), 0);
  218. nsavi::video_format *format = (nsavi::video_format *)stream.stream_format;
  219. wchar_t fourcc[5] = {0};
  220. MakeStringFromFOURCC(fourcc, format->compression);
  221. list_view.SetItemText(n, COLUMN_CODEC_ID, fourcc);
  222. const wchar_t *codec_name = FindKnownName(known_video_codecs, sizeof(known_video_codecs)/sizeof(known_video_codecs[0]), format->compression);
  223. if (codec_name)
  224. list_view.SetItemText(n, COLUMN_CODEC_NAME, codec_name);
  225. else
  226. list_view.SetItemText(n, COLUMN_CODEC_NAME, fourcc);
  227. wchar_t description[256] = {0};
  228. GetVideoCodecDescription(description, 256, stream.stream_format);
  229. list_view.SetItemText(n, COLUMN_DESCRIPTION, description);
  230. }
  231. break;
  232. default:
  233. {
  234. wchar_t fourcc[5] = {0};
  235. MakeStringFromFOURCC(fourcc, stream.stream_header->stream_type);
  236. n = list_view.AppendItem(fourcc, 0);
  237. }
  238. break;
  239. }
  240. if (stream.stream_name)
  241. {
  242. //const char *name = (const char *) (((const uint8_t *)stream.stream_name) + 4);
  243. // TODO: need AutoWideN before this is safe
  244. // list_view.SetItemText(n, COLUMN_STREAM_NAME, AutoWide(name, CP_UTF8));
  245. }
  246. }
  247. }
  248. }
  249. return 1;
  250. case WM_SIZE:
  251. {
  252. RECT r;
  253. GetClientRect(hwndDlg, &r);
  254. SetWindowPos(GetDlgItem(hwndDlg, IDC_TRACKLIST), HWND_TOP, r.left, r.top, r.right, r.bottom, SWP_NOACTIVATE);
  255. }
  256. break;
  257. }
  258. return 0;
  259. }
  260. struct InfoDialogContext
  261. {
  262. nsavi::Metadata *metadata;
  263. HWND active_tab;
  264. };
  265. static VOID WINAPI OnSelChanged(HWND hwndDlg, HWND hwndTab, InfoDialogContext *context)
  266. {
  267. if (context->active_tab)
  268. {
  269. DestroyWindow(context->active_tab);
  270. }
  271. int selection = TabCtrl_GetCurSel(hwndTab);
  272. switch(selection)
  273. {
  274. case 0:
  275. context->active_tab = WASABI_API_CREATEDIALOGPARAMW(IDD_TRACKS, hwndDlg, InfoDialog_Metadata, (LPARAM)context->metadata);
  276. break;
  277. case 1:
  278. context->active_tab = WASABI_API_CREATEDIALOGPARAMW(IDD_TRACKS, hwndDlg, InfoDialog_Tracks, (LPARAM)context->metadata);
  279. break;
  280. }
  281. RECT r;
  282. GetWindowRect(hwndTab,&r);
  283. TabCtrl_AdjustRect(hwndTab,FALSE,&r);
  284. MapWindowPoints(NULL,hwndDlg,(LPPOINT)&r,2);
  285. SetWindowPos(context->active_tab,HWND_TOP,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOACTIVATE);
  286. ShowWindow(context->active_tab, SW_SHOWNA);
  287. if (GetFocus() != hwndTab)
  288. {
  289. SetFocus(context->active_tab);
  290. }
  291. }
  292. INT_PTR CALLBACK InfoDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  293. {
  294. switch (uMsg)
  295. {
  296. case WM_INITDIALOG:
  297. {
  298. HWND hwndTab = GetDlgItem(hwndDlg,IDC_TAB1);
  299. InfoDialogContext *context = (InfoDialogContext *)calloc(1, sizeof(InfoDialogContext));
  300. context->metadata = (nsavi::Metadata *)lParam;
  301. context->active_tab = 0;
  302. SetWindowLongPtr(hwndDlg,GWLP_USERDATA, (LPARAM)context);
  303. TCITEMW tie = {0};
  304. tie.mask = TCIF_TEXT;
  305. tie.pszText = WASABI_API_LNGSTRINGW(IDS_TAB_METADATA);
  306. SendMessageW(hwndTab, TCM_INSERTITEMW, 0, (LPARAM)&tie);
  307. tie.pszText = WASABI_API_LNGSTRINGW(IDS_TAB_TRACKS);
  308. SendMessageW(hwndTab, TCM_INSERTITEMW, 1, (LPARAM)&tie);
  309. OnSelChanged(hwndDlg, hwndTab, context);
  310. }
  311. return 1;
  312. case WM_DESTROY:
  313. {
  314. InfoDialogContext *context = (InfoDialogContext *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
  315. free(context);
  316. }
  317. break;
  318. case WM_NOTIFY:
  319. {
  320. LPNMHDR lpn = (LPNMHDR) lParam;
  321. if (lpn && lpn->code==TCN_SELCHANGE)
  322. {
  323. InfoDialogContext *context = (InfoDialogContext *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
  324. OnSelChanged(hwndDlg,GetDlgItem(hwndDlg,IDC_TAB1),context);
  325. }
  326. }
  327. break;
  328. case WM_COMMAND:
  329. switch (LOWORD(wParam))
  330. {
  331. case IDOK:
  332. {
  333. EndDialog(hwndDlg,0);
  334. }
  335. break;
  336. case IDCANCEL:
  337. {
  338. EndDialog(hwndDlg,1);
  339. }
  340. break;
  341. }
  342. break;
  343. }
  344. return 0;
  345. }