Есть два момента которые требуют улучшения:
1. Нельзя прервать процесс создания миниатюры. Как минимум должна быть возможность закрыть плеер.
2. Плохое качество миниатюр.
[merge_posts_bbcode]Добавлено: 2016-06-25 10:52:34[/merge_posts_bbcode]
По 1-у пункту. Хотелось бы некий универсальный механизм для завершения разных некритичных операций при закрытии плеера.
Ну по поводу пункта 1 думаю не сложно добавить обработку нажатия клавиш, а лучше запускать в отдельном потоке и разруливать через евенты.
По поводу пункта 2 - тут надо переписать/заменить алгоритм уменьшения. Может надо использовать что-то из vd. Надо проверить.
Я думал о неком глобальном сообщении, проверку которого втравляем в цикл генерации миниатюр. Вроде что-то подобное у нас где-то используется.
Не стоит добавлять обработчик клавиш в SaveThumbnails.
Ну и я сказал что евенты. Но тогда надо запускать в отдельном потоке - чтобы это дело обрабатывать. Это не трудно реализовать :)
По поводу качества - надо попробовать использовать BitBltFromRGBToRGBStretch(), с помощью этой функции уменьшать - а уже потом просто скопировать данные из полученных в общие.
[merge_posts_bbcode]Добавлено: 2016-06-25 18:43:09[/merge_posts_bbcode]
Проверил - использование BitBltFromRGBToRGBStretch() дает более "гладкую" картинку, более мягкую. Правда меня смущает вот этот кусок кода, не могу понять как просто данные перенести из полученной маленькой картинки в большую общую, в нужные координаты.
for (DWORD h = r.bottom - r.top, y = 0, yd = (sh << 8) / h; h > 0; y += yd, h--) {
DWORD yf = y & 0xff;
DWORD yi = y >> 8;
DWORD* s0 = (DWORD*)(src + (int)yi * sp);
DWORD* s1 = (DWORD*)(src + (int)yi * sp + sp);
DWORD* d = (DWORD*)dst;
for (DWORD w = r.right - r.left, x = 0, xd = (sw << 8) / w; w > 0; x += xd, w--) {
DWORD xf = x & 0xff;
DWORD xi = x >> 8;
DWORD c0 = s0[xi];
DWORD c1 = s0[xi + 1];
DWORD c2 = s1[xi];
DWORD c3 = s1[xi + 1];
c0 = ((c0&0xff00ff) + ((((c1&0xff00ff) - (c0&0xff00ff)) * xf) >> 8)) & 0xff00ff
| ((c0&0x00ff00) + ((((c1&0x00ff00) - (c0&0x00ff00)) * xf) >> 8)) & 0x00ff00;
c2 = ((c2&0xff00ff) + ((((c3&0xff00ff) - (c2&0xff00ff)) * xf) >> 8)) & 0xff00ff
| ((c2&0x00ff00) + ((((c3&0x00ff00) - (c2&0x00ff00)) * xf) >> 8)) & 0x00ff00;
c0 = ((c0&0xff00ff) + ((((c2&0xff00ff) - (c0&0xff00ff)) * yf) >> 8)) & 0xff00ff
| ((c0&0x00ff00) + ((((c2&0x00ff00) - (c0&0x00ff00)) * yf) >> 8)) & 0x00ff00;
*d++ = c0;
}
dst += dp;
}
Этот код тебе вообще не нужно трогать.
Цитата: V0ltЭтот код тебе вообще не нужно трогать.
Еще как нужно - это как раз и есть оригинальный код ресайза :)
[merge_posts_bbcode]Добавлено: 2016-06-25 20:51:00[/merge_posts_bbcode]
Вот собранный билд + патч. Ресайз делается силами BitBltFromRGBToRGBStretch().
https://yadi.sk/d/2tm9lUyhsnHabПравда что-то разницы в качестве я не заметил, но зато должно быть немного по шустрее делаться ресайз, все таки там используются различные оптимизации.
По поводу отмены создания миниатюр - тут есть нюанс, пока он выполняется не работает нажатия ни кнопок ни меню. Запустить в отдельном потоке тоже не получится - нам необходимо дождаться его окончания и только после что-то делать дальше.
Неожиданно. Мне подумалось что это тень. :)
Что-то твой билд еще хуже генерирует миниатюры.
Что-то по поводу хуже я не заметил. Выложи свои файлики-миниатюр - с SVN и с моего билда. Гляну.
У себя я сохраняю только в .png
svn1666 - (http://s45.radikal.ru/i107/1606/fc/ab5874ed0521t.jpg) (http://s45.radikal.ru/i107/1606/fc/ab5874ed0521.png)
test - (http://s48.radikal.ru/i119/1606/f9/80c4276fe5dat.jpg) (http://s48.radikal.ru/i119/1606/f9/80c4276fe5da.png)
Ну сравнение на 8К - это уже перебор да и не актуально :) В любом случае ни там ни там ни чего не видно.
Вот сравнил на 4K
svn:
(http://s017.radikal.ru/i413/1606/f1/bd14d7d43db9t.jpg) (http://radikal.ru/fp/6d79a9851e6e43a6906282d1e68be877)
test:
(http://i079.radikal.ru/1606/85/0ae6e90d485ft.jpg) (http://radikal.ru/fp/9607ad0eba024299b154b8af4bc12d99)
А вот так нагляднее - http://screenshotcomparison.com/comparison/176601
Не обязательно 8k, главное сильное уменьшение, просто на этом сэмпле видно разницу.
Да и особого ускорения от BitBltFromRGBToRGBStretch() не будет. Код который сейчас используется простой как валенок.
Ну тогда закрываем тему - ни улучшить качество картинки, ни отменить создание миниатюр мы не сможем.
Все можем, только не сразу.
Ну в принципе ты прав - погуглил и нашел несколько алгоритмов ресайза. Взял один из них и проверил качество, вот что вышло на 4K
http://screenshotcomparison.com/comparison/176605
более "смазанное", зато нет этих разломов, белых ломанных линий и т.д.
В принципе GDI умеет уменьшать растровые картинки и выводить результат в нужный прямоугольник. Только нужно проверить, как оно это делает.
PS: У меня синтаксис GDI мозг не принимает. Там во всех функциях нужно записать HDC, который порой вообще непонятно откуда брать, т.к. в примерах оно появляется волшебным образом. Да и название дебильное device context. :mad:
а можно приделать сообщение о том, что миниатюры рендерятся и юзер должен подождать?
в идеале еще и прогрессбар процесса этого вывести, тогда не будут возникать позывы закрыть плеер в процессе их создания.
Если что - вот тестовый билд с другим алгоритмом уменьшения, сравниваем
https://yadi.sk/d/yl6QXfawsnrXu
Aleksoid1978
На этом билде хорошо.
(http://s41.radikal.ru/i091/1606/bd/294e9bdd08dat.jpg) (http://s41.radikal.ru/i091/1606/bd/294e9bdd08da.png)
Angel
Я думал о небольшом модальном окне с прогресс-баром и кнопкой "Oтмена". Это пока самый оптимальный вариант.
А я предлагаю примерно как с диалогом сохранения - будет и кнопка отмена, и прогресс бар(правда не плавный - но все равно).
[merge_posts_bbcode]Добавлено: 2016-06-26 13:22:00[/merge_posts_bbcode]
Тоже проверил на 8K - http://screenshotcomparison.com/comparison/176652
Разница на лицо :) Думаю надо внедрять новый алгоритм.
Внедряй, только просьба безо всякой косметики, а то потом в логе изменений трудно понять, что поменялось.
Есть описание алгоритма?
Описания как такового нет, есть комментарии в сырцах и страничка где это взято, её укажу как источник.
[merge_posts_bbcode]Добавлено: 2016-06-27 15:15:13[/merge_posts_bbcode]
Еще вот тут нашел сырцы https://github.com/artcom/y60/tree/master/netsrc/paintlib/src/Filter
Там есть pl2passscale.h - 2-х проходный ресайзер, сперва по горизонтали, потом по вертикали.
Но т.к. у нас уже хорошее качество - не стал проверять, думаю вряд ли может получиться сильно лучше.
[merge_posts_bbcode]Добавлено: 2016-06-28 17:15:00[/merge_posts_bbcode]
Предлагаю текстовый билд с диалогом - https://yadi.sk/d/ZQDe5J0JsqcMp
и так же патч для этого дела - https://yadi.sk/d/MJhOnIb4sqcPn
Не пугаться - в патче еще изменения немного не в тему, изменены проверки работы оператора new. На самом деле вот такой код:
BYTE* p = DNew BYTE[size];
if (!p) {
return;
}
не работает, т.к. в любом случае переменная p не будет нулевой и проверка не пройдет. А вот если не получиться память выделить - тогда сработает CMemoryException, что и надо отловить. Там конечно размеры выделяются маленькие и по идее такое никогда не сработает - но в любом случае правильнее использовать try {} catch {}.
[merge_posts_bbcode]Добавлено: 2016-06-28 17:32:28[/merge_posts_bbcode]
Там правда есть нюансы:
1) - Плавное изменение ползунка не получиться, как и моментальная отмена операции по нажатию на кнопку.
2) - После отмены не возвращается на прежнее место. Пока не копался.
Спасибо за патч. У тебя слишком много лишнего в новом потоке. Стоп и выключение звука, а также возврат к исходному лучше оставить в основном окне.
Я переработал свой вариант, мне надо немного потестить и выложу сборку.
Да я по быстрому просто перенёс код.
По поводу проверки/тестирования - советую обратить особое внимание обработки нажатия Отмены во время построения. Ну чтобы не было косяков и зависаний.
Сборку выкладывай сразу с патчем.
Сборку залил.
Все отрабатывает корректно, кроме зависания MPC Audio Renderer. Тот чего-то пытается ждать какие-то данные на паузе.
Еще непонятно назначение этого блока
HANDLE hGraphEvent = NULL;
pMainFrm->m_pME->GetEventHandle((OAEVENT*)&hGraphEvent);
while (hGraphEvent && WaitForSingleObject(hGraphEvent, INFINITE) == WAIT_OBJECT_0) {
LONG evCode = 0;
LONG_PTR evParam1, evParam2;
while (pMainFrm->m_pME && SUCCEEDED(pMainFrm->m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) {
pMainFrm->m_pME->FreeEventParams(evCode, evParam1, evParam2);
if (EC_STEP_COMPLETE == evCode) {
hGraphEvent = NULL;
}
}
}
Поэтому оставил как есть. Если будет информация, то напишу комментарий.
1 - раньше были зависания с нашим аудио выводом ??
2 - тот код ждет завершения шага от видео-рендерера.
[merge_posts_bbcode]Добавлено: 2016-06-30 08:52:21[/merge_posts_bbcode]
И вот еще что "не красиво" - ты в самом CTaskDlg вызываешь AfxMessageBox(). Выглядит некрасиво. Лучше как я делал - закрывать диалог и уже после показывать сообщение.
Кстати, можно сохранять миниатюры на стопе. Вроде не зависает.
Я потестирую еще.
[merge_posts_bbcode]Добавлено: 2016-06-30 06:44:08[/merge_posts_bbcode]
AfxMessageBox() посмотрю...
[merge_posts_bbcode]Добавлено: 2016-07-04 22:13:42[/merge_posts_bbcode]
В общем проблема оказалась в том, что у нас получается два обработчика событий графа. Это неправильно, т.к. в результате до каждого обработчика доходит лишь часть событий.
Исправил в r1706.