A certain game application requires both.
-- v2: winegstreamer: Always use bottom-up for AVI RGB videos. winegstreamer: Add ARGB32 format support for 32 bpp AVI videos. quartz/tests: Add tests for 32 bpp AVI videos.
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/quartz/tests/avisplit.c | 107 +++++++++++++++++++++++++++++++ dlls/quartz/tests/rsrc.rc | 4 ++ dlls/quartz/tests/test_32bpp.avi | Bin 0 -> 11954 bytes 3 files changed, 111 insertions(+) create mode 100644 dlls/quartz/tests/test_32bpp.avi
diff --git a/dlls/quartz/tests/avisplit.c b/dlls/quartz/tests/avisplit.c index f7fadb606c4..c47c6f3f99a 100644 --- a/dlls/quartz/tests/avisplit.c +++ b/dlls/quartz/tests/avisplit.c @@ -1767,6 +1767,112 @@ static void test_streaming(const WCHAR *resname) winetest_pop_context(); }
+static void test_32bpp_media_types(void) +{ + static const VIDEOINFOHEADER expect_vih = + { + .AvgTimePerFrame = 1000 * 10000, + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = 24, + .bmiHeader.biPlanes = 1, + .bmiHeader.biBitCount = 32, + .bmiHeader.biCompression = BI_RGB, + .bmiHeader.biSizeImage = 32 * 24 * 32 / 8, + }; + + const WCHAR *filename = load_resource(L"test_32bpp.avi"); + IBaseFilter *filter = create_avi_splitter(); + IFilterGraph2 *graph = connect_input(filter, filename); + IEnumMediaTypes *enummt; + VIDEOINFOHEADER *vih; + AM_MEDIA_TYPE *pmt; + HRESULT hr; + ULONG ref; + IPin *pin; + BOOL ret; + + IBaseFilter_FindPin(filter, L"Stream 00", &pin); + + hr = IPin_EnumMediaTypes(pin, &enummt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + /* 1: ARGB32 */ + hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video), "Got major type %s\n", + wine_dbgstr_guid(&pmt->majortype)); + todo_wine ok(IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_ARGB32), "Got subtype %s\n", + wine_dbgstr_guid(&pmt->subtype)); + ok(!pmt->bFixedSizeSamples, "Got fixed size %d.\n", pmt->bFixedSizeSamples); + ok(pmt->lSampleSize == 1, "Got sample size %lu.\n", pmt->lSampleSize); + ok(IsEqualGUID(&pmt->formattype, &FORMAT_VideoInfo), "Got format type %s.\n", + wine_dbgstr_guid(&pmt->formattype)); + ok(!pmt->pUnk, "Got pUnk %p.\n", pmt->pUnk); + ok(pmt->cbFormat == sizeof(VIDEOINFOHEADER), "Got format size %lu.\n", pmt->cbFormat); + todo_wine ok(!memcmp(pmt->pbFormat, &expect_vih, sizeof(VIDEOINFOHEADER)), "Format blocks didn't match.\n"); + + vih = (VIDEOINFOHEADER *)pmt->pbFormat; + ok(vih->bmiHeader.biSize == expect_vih.bmiHeader.biSize, "Got biSize %lu.\n", vih->bmiHeader.biSize); + ok(vih->bmiHeader.biWidth == expect_vih.bmiHeader.biWidth, "Got biWidth %ld.\n", vih->bmiHeader.biWidth); + todo_wine ok(vih->bmiHeader.biHeight == expect_vih.bmiHeader.biHeight, "Got biHeight %ld.\n", vih->bmiHeader.biHeight); + + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + FreeMediaType(pmt); + + /* 2: RGB32 */ + hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_FALSE) goto done; + + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video), "Got major type %s\n", + wine_dbgstr_guid(&pmt->majortype)); + ok(IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB32), "Got subtype %s\n", + wine_dbgstr_guid(&pmt->subtype)); + ok(!pmt->bFixedSizeSamples, "Got fixed size %d.\n", pmt->bFixedSizeSamples); + todo_wine ok(!pmt->bTemporalCompression, "Got temporal compression %d.\n", pmt->bTemporalCompression); + ok(pmt->lSampleSize == 1, "Got sample size %lu.\n", pmt->lSampleSize); + ok(IsEqualGUID(&pmt->formattype, &FORMAT_VideoInfo), "Got format type %s.\n", + wine_dbgstr_guid(&pmt->formattype)); + ok(!pmt->pUnk, "Got pUnk %p.\n", pmt->pUnk); + ok(pmt->cbFormat == sizeof(VIDEOINFOHEADER), "Got format size %lu.\n", pmt->cbFormat); + todo_wine ok(!memcmp(pmt->pbFormat, &expect_vih, sizeof(VIDEOINFOHEADER)), "Format blocks didn't match.\n"); + + vih = (VIDEOINFOHEADER *)pmt->pbFormat; + ok(vih->bmiHeader.biSize == expect_vih.bmiHeader.biSize, "Got biSize %lu.\n", vih->bmiHeader.biSize); + ok(vih->bmiHeader.biWidth == expect_vih.bmiHeader.biWidth, "Got biWidth %ld.\n", vih->bmiHeader.biWidth); + todo_wine ok(vih->bmiHeader.biHeight == expect_vih.bmiHeader.biHeight, "Got biHeight %ld.\n", vih->bmiHeader.biHeight); + + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + FreeMediaType(pmt); + +done: + hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + IEnumMediaTypes_Release(enummt); + IPin_Release(pin); + + IFilterGraph2_Release(graph); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ret = DeleteFileW(filename); + ok(ret, "Failed to delete file, error %lu.\n", GetLastError()); +} + START_TEST(avisplit) { IBaseFilter *filter; @@ -1793,6 +1899,7 @@ START_TEST(avisplit) test_seeking(); test_streaming(L"test.avi"); test_streaming(L"test_cinepak.avi"); + test_32bpp_media_types();
CoUninitialize(); } diff --git a/dlls/quartz/tests/rsrc.rc b/dlls/quartz/tests/rsrc.rc index a15520d21ac..e11ef4d006e 100644 --- a/dlls/quartz/tests/rsrc.rc +++ b/dlls/quartz/tests/rsrc.rc @@ -43,3 +43,7 @@ test2.mpg RCDATA "test2.mpg" /* ffmpeg -f lavfi -i smptebars -t 5 -r 1 -f avi -vcodec cinepak -pix_fmt rgb24 -vf scale=32x24 test_cinepak.avi */ /* @makedep: test_cinepak.avi */ test_cinepak.avi RCDATA "test_cinepak.avi" + +/* ffmpeg -f lavfi -i smptebars -t 2 -r 1 -f avi -vcodec rawvideo -pix_fmt rgb32 -vf scale=32x24,vflip -flipped_raw_rgb 1 test_32bpp.avi */ +/* @makedep: test_32bpp.avi */ +test_32bpp.avi RCDATA "test_32bpp.avi" diff --git a/dlls/quartz/tests/test_32bpp.avi b/dlls/quartz/tests/test_32bpp.avi new file mode 100644 index 0000000000000000000000000000000000000000..ddf11f8afef5fa9f239ee343ff4f51838f4df956 GIT binary patch literal 11954 zcmWIYbaPv!$H3qi=BeQ08609E#K4e|Qk0WemYHF}z`)?(#LvLM!vF>XoD2+1U={-d zBbXLoP+(wSkN~q$36NP21Q-~KONw%eONzi|m1U+BqpE_K12GF~HV*^C|NsC0!_+A- zNPx^p(_mm=0AZMYj9{A?;BJGd2hm=ke%=xS3=AwF4g&*&fk8?#lsQU`hQMeDjE2By z2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mu5GX4sDsVyaD`@-yHm<<Tzycmw0F7yY z#6dJn4n!kq12aKm4J?cd4EZU!IVrh089%_HBa;A)`A9J^FnId8`FjSth43*jF!&^v zrI{J%8Jg)C8W=EuLhA?f$PArPUyp{sNDl!}2_YiEz>u3?mI)q}<zZk*w`KSb!Wp&< z|3NsygyDZrhQa^;|Ns5}|Nrm*U;iK&G%CDp?#ll;495S<7;OJnG1!4|ESKqj4+aI$ zi1B|0Mg|DYfJw8lvHb^O1~fU4-5?CI8-(d?f3g+Be-KWwX7~@np+*e<JJa<3|Nr;* z|Gz)K|9^*KkpH*LS@A!U!Qg)}gVp~s25T^m;xPX2${>f+-!T6&voQY$VHh7qgX{)j zkli3mZ~K$18UBNCvJJz35C+-bm97u+E;tSR`v33$&;NhH{H^m>{7+}l`(MOh`M;9E z7K~#!P5!$P;eQrZmj6u5Oc>#mWy<g$gtN^U{)2F^9>f2pSgrrB-@N?)^40VI&!4^e z|K|1k|NmeA|G#a*>i>D*uy^{O%U}-1LF{_}?HQ#1GqN%KXXjz~&%+DB?Chv%5ES;D zT%7-TczOPF^KirQ76yj@AiR@-;r}iMhX3}g4F4?{82)pJ^89BP;r?&UVEw;XtN8yJ z?sNYSF&_E9f^FIV84T0@b1|^}=VoC4&&t3I_EUZl!~bO~rT=f(%J6^VHirM5J$nBY zRbXy__}k6h_5YR~JN~cPumO(ua&!F$;X_<p|3TPRNa()-E9-v-0d_FfVbK4dq>}po zDC?I0M_4xhUoW}n{~Wgd{|r2g5X{H$pMjI%e_aK`|1Ik@{vY1T@c-y`rvH<B9sg^A z?HB&fz##IUfr0tIhg;zPV>`D0-?w4?|9u-afbp)iYyN}qfi-LXA6&ckzxC!#|MiwF z{m-y=D;S6DtoU!YIO+fKwaoudtYi7VWE1cIxvSa!Gpu2N;B^fD88$HdpK8?kzels- z|7o@j|Ie^*{GTDX^S>X%{QnFLoBlH}Z2Ygq()(YTq3!=3ZjS$Zc{u;?;pPJ4-TU|b z2jK(z_WcK8o1;hn>+jg{pJD$AFpfOm@ZV}f;{W6O82+C;!0><ZVTS*6_cHuv*vIgn zVL!uvhJy_M84fZ0pP@bTe}{DE|I-Xd{-0qu`agx`*#97gE&mx9j)1WN>zw}z3_bsM zGcf$$%fJApLF_$y_xuOp1ABJ=2Vv_&2mkAB-SVGd_Yp7-KU4SLa$Umz<9itXpV-Ur zfAIl^|8sXS{Abt$#UQurXZSx|XWIWxxsLy*84mtG!*J+-D*KWDK@1!JGcX(kV|~_H z{}o5=2Z#G;_>ZPPP~HP!P~HP!P~HRK(fl`B{tQI<dvMS0{~&C0_|Sj-ZCn2{>^Ta? z5vS|^Tdzy}e_{{A|5N)I{x3Pmh+6(b>!BGs)BktLf$E=w|IacU{-4Hn<bN<y`ES5B z8(jYHL92iE?c4Vsgb(lC`yYhujvV=Kux;CahCRo?IPy%xf1CBm|4;6P*uV4u<Nx`{ z^$*DY0}TIX>dyGzE#LM3EW@Gy=NJzEPiH^&KZIfPe+Gs_U~I@f=f4s|@Be)a4FC5- z-2f_wNBaSgHX5i64#J=|I0%E<!K3|v(SE>aKVY;U0O|{j_5()yL8JY^(SGpp(Q$xb qJq`lu1Ay>I>jz|}R2YJ0SV8>(0S4&mZ63(#Z4jRav<jVvfdK%xX4VV<
literal 0 HcmV?d00001
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/quartz/tests/avisplit.c | 4 ++-- dlls/winegstreamer/quartz_parser.c | 26 +++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/dlls/quartz/tests/avisplit.c b/dlls/quartz/tests/avisplit.c index c47c6f3f99a..c6e5687f8e2 100644 --- a/dlls/quartz/tests/avisplit.c +++ b/dlls/quartz/tests/avisplit.c @@ -1802,7 +1802,7 @@ static void test_32bpp_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video), "Got major type %s\n", wine_dbgstr_guid(&pmt->majortype)); - todo_wine ok(IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_ARGB32), "Got subtype %s\n", + ok(IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_ARGB32), "Got subtype %s\n", wine_dbgstr_guid(&pmt->subtype)); ok(!pmt->bFixedSizeSamples, "Got fixed size %d.\n", pmt->bFixedSizeSamples); ok(pmt->lSampleSize == 1, "Got sample size %lu.\n", pmt->lSampleSize); @@ -1828,7 +1828,7 @@ static void test_32bpp_media_types(void)
/* 2: RGB32 */ hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); if (hr == S_FALSE) goto done;
ok(hr == S_OK, "Got hr %#lx.\n", hr); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index abfe4763697..d8462770bb5 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -2436,6 +2436,19 @@ static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; FreeMediaType(&pad_mt); + + /* For 32 bpp AVI files, also accept ARGB32 format. */ + if (hr == S_FALSE + && format.major_type == WG_MAJOR_TYPE_VIDEO + && format.u.video.format == WG_VIDEO_FORMAT_BGRx) + { + format.u.video.format = WG_VIDEO_FORMAT_BGRA; + if (!amt_from_wg_format(&pad_mt, &format, false)) + return E_OUTOFMEMORY; + hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; + FreeMediaType(&pad_mt); + } + return hr; }
@@ -2444,9 +2457,20 @@ static HRESULT avi_splitter_source_get_media_type(struct parser_source *pin, { struct wg_format format;
- if (index > 0) + if (index > 1) return VFW_S_NO_MORE_ITEMS; + wg_parser_stream_get_current_format(pin->wg_stream, &format); + if (format.major_type == WG_MAJOR_TYPE_VIDEO + && format.u.video.format == WG_VIDEO_FORMAT_BGRx) + { + /* Offer ARGB32 format as the first candidate for 32 bpp AVI files. */ + if (index == 0) + format.u.video.format = WG_VIDEO_FORMAT_BGRA; + } + else if (index > 0) + return VFW_S_NO_MORE_ITEMS; + if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK;
From: Akihiro Sagawa sagawa.aki@gmail.com
GStreamer caps don't provide the scan direction of AVI files, and some downstream filters don't handle top-down correctly. --- dlls/quartz/tests/avisplit.c | 16 ++++------------ dlls/winegstreamer/quartz_parser.c | 4 ++++ 2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/dlls/quartz/tests/avisplit.c b/dlls/quartz/tests/avisplit.c index c6e5687f8e2..cb756a07c5d 100644 --- a/dlls/quartz/tests/avisplit.c +++ b/dlls/quartz/tests/avisplit.c @@ -1810,16 +1810,12 @@ static void test_32bpp_media_types(void) wine_dbgstr_guid(&pmt->formattype)); ok(!pmt->pUnk, "Got pUnk %p.\n", pmt->pUnk); ok(pmt->cbFormat == sizeof(VIDEOINFOHEADER), "Got format size %lu.\n", pmt->cbFormat); - todo_wine ok(!memcmp(pmt->pbFormat, &expect_vih, sizeof(VIDEOINFOHEADER)), "Format blocks didn't match.\n"); - - vih = (VIDEOINFOHEADER *)pmt->pbFormat; - ok(vih->bmiHeader.biSize == expect_vih.bmiHeader.biSize, "Got biSize %lu.\n", vih->bmiHeader.biSize); - ok(vih->bmiHeader.biWidth == expect_vih.bmiHeader.biWidth, "Got biWidth %ld.\n", vih->bmiHeader.biWidth); - todo_wine ok(vih->bmiHeader.biHeight == expect_vih.bmiHeader.biHeight, "Got biHeight %ld.\n", vih->bmiHeader.biHeight); + ok(!memcmp(pmt->pbFormat, &expect_vih, sizeof(VIDEOINFOHEADER)), "Format blocks didn't match.\n");
hr = IPin_QueryAccept(pin, pmt); ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ vih = (VIDEOINFOHEADER *)pmt->pbFormat; vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight; hr = IPin_QueryAccept(pin, pmt); ok(hr == S_FALSE, "Got hr %#lx.\n", hr); @@ -1843,16 +1839,12 @@ static void test_32bpp_media_types(void) wine_dbgstr_guid(&pmt->formattype)); ok(!pmt->pUnk, "Got pUnk %p.\n", pmt->pUnk); ok(pmt->cbFormat == sizeof(VIDEOINFOHEADER), "Got format size %lu.\n", pmt->cbFormat); - todo_wine ok(!memcmp(pmt->pbFormat, &expect_vih, sizeof(VIDEOINFOHEADER)), "Format blocks didn't match.\n"); - - vih = (VIDEOINFOHEADER *)pmt->pbFormat; - ok(vih->bmiHeader.biSize == expect_vih.bmiHeader.biSize, "Got biSize %lu.\n", vih->bmiHeader.biSize); - ok(vih->bmiHeader.biWidth == expect_vih.bmiHeader.biWidth, "Got biWidth %ld.\n", vih->bmiHeader.biWidth); - todo_wine ok(vih->bmiHeader.biHeight == expect_vih.bmiHeader.biHeight, "Got biHeight %ld.\n", vih->bmiHeader.biHeight); + ok(!memcmp(pmt->pbFormat, &expect_vih, sizeof(VIDEOINFOHEADER)), "Format blocks didn't match.\n");
hr = IPin_QueryAccept(pin, pmt); ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ vih = (VIDEOINFOHEADER *)pmt->pbFormat; vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight; hr = IPin_QueryAccept(pin, pmt); ok(hr == S_FALSE, "Got hr %#lx.\n", hr); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index d8462770bb5..6ba0b2128f2 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -2432,6 +2432,8 @@ static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const HRESULT hr;
wg_parser_stream_get_current_format(pin->wg_stream, &format); + if (wg_video_format_is_rgb(format.u.video.format)) + format.u.video.height = -format.u.video.height; if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -2471,6 +2473,8 @@ static HRESULT avi_splitter_source_get_media_type(struct parser_source *pin, else if (index > 0) return VFW_S_NO_MORE_ITEMS;
+ if (wg_video_format_is_rgb(format.u.video.format)) + format.u.video.height = -format.u.video.height; if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK;