From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/mfplat.c | 1 + dlls/winegstreamer/quartz_parser.c | 140 +++++++++++++++++++++-------- dlls/winegstreamer/unixlib.h | 6 ++ dlls/winegstreamer/wg_format.c | 55 ++++++++++++ dlls/winegstreamer/wg_transform.c | 2 + dlls/winegstreamer/wm_reader.c | 4 + 6 files changed, 173 insertions(+), 35 deletions(-)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index c7906a8bc1f..0e1d489d8e5 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -565,6 +565,7 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: + case WG_MAJOR_TYPE_VIDEO_MPEG1: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index cb18c951013..d5af7b29bae 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -280,46 +280,50 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo
#define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
+unsigned int wg_format_get_bytes_for_uncompressed(wg_video_format format, unsigned int width, unsigned int height) +{ + switch (format) + { + case WG_VIDEO_FORMAT_BGRA: + case WG_VIDEO_FORMAT_BGRx: + case WG_VIDEO_FORMAT_AYUV: + return width * height * 4; + + case WG_VIDEO_FORMAT_BGR: + return ALIGN(width * 3, 4) * height; + + case WG_VIDEO_FORMAT_RGB15: + case WG_VIDEO_FORMAT_RGB16: + case WG_VIDEO_FORMAT_UYVY: + case WG_VIDEO_FORMAT_YUY2: + case WG_VIDEO_FORMAT_YVYU: + return ALIGN(width * 2, 4) * height; + + case WG_VIDEO_FORMAT_I420: + case WG_VIDEO_FORMAT_YV12: + return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ + + 2 * ALIGN((width + 1) / 2, 4) * ((height + 1) / 2); /* U and V planes */ + + case WG_VIDEO_FORMAT_NV12: + return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ + + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */ + + case WG_VIDEO_FORMAT_UNKNOWN: + FIXME("Cannot guess maximum sample size for unknown video format.\n"); + return 0; + } + + assert(0); + return 0; +} + unsigned int wg_format_get_max_size(const struct wg_format *format) { switch (format->major_type) { case WG_MAJOR_TYPE_VIDEO: - { - unsigned int width = format->u.video.width, height = abs(format->u.video.height); - - switch (format->u.video.format) - { - case WG_VIDEO_FORMAT_BGRA: - case WG_VIDEO_FORMAT_BGRx: - case WG_VIDEO_FORMAT_AYUV: - return width * height * 4; - - case WG_VIDEO_FORMAT_BGR: - return ALIGN(width * 3, 4) * height; - - case WG_VIDEO_FORMAT_RGB15: - case WG_VIDEO_FORMAT_RGB16: - case WG_VIDEO_FORMAT_UYVY: - case WG_VIDEO_FORMAT_YUY2: - case WG_VIDEO_FORMAT_YVYU: - return ALIGN(width * 2, 4) * height; - - case WG_VIDEO_FORMAT_I420: - case WG_VIDEO_FORMAT_YV12: - return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ - + 2 * ALIGN((width + 1) / 2, 4) * ((height + 1) / 2); /* U and V planes */ - - case WG_VIDEO_FORMAT_NV12: - return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */ - + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */ - - case WG_VIDEO_FORMAT_UNKNOWN: - FIXME("Cannot guess maximum sample size for unknown video format.\n"); - return 0; - } - break; - } + return wg_format_get_bytes_for_uncompressed(format->u.video.format, + format->u.video.width, abs(format->u.video.height));
case WG_MAJOR_TYPE_VIDEO_CINEPAK: /* Both ffmpeg's encoder and a Cinepak file seen in the wild report @@ -327,6 +331,13 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) * but as long as every sample fits into our allocator, we're fine. */ return format->u.video_cinepak.width * format->u.video_cinepak.height * 3;
+ case WG_MAJOR_TYPE_VIDEO_MPEG1: + /* Estimated max size of a compressed video frame. + * There's no way to no way to know the real upper bound, + * so let's just use the decompressed size and hope it works. */ + return wg_format_get_bytes_for_uncompressed(WG_VIDEO_FORMAT_YV12, + format->u.video_mpeg1.width, format->u.video_mpeg1.height); + case WG_MAJOR_TYPE_AUDIO: { unsigned int rate = format->u.audio.rate, channels = format->u.audio.channels; @@ -595,6 +606,36 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form return true; }
+static bool amt_from_wg_format_video_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_format *format) +{ + MPEG1VIDEOINFO *video_format; + uint32_t frame_time; + + if (!(video_format = CoTaskMemAlloc(sizeof(*video_format)))) + return false; + + mt->majortype = MEDIATYPE_Video; + mt->subtype = MEDIASUBTYPE_MPEG1Payload; + mt->bTemporalCompression = TRUE; + mt->lSampleSize = 1; + mt->formattype = FORMAT_MPEGVideo; + mt->cbFormat = sizeof(MPEG1VIDEOINFO); + mt->pbFormat = (BYTE *)video_format; + + memset(video_format, 0, sizeof(*video_format)); + if ((frame_time = MulDiv(10000000, format->u.video_mpeg1.fps_d, format->u.video_mpeg1.fps_n)) != -1) + video_format->hdr.AvgTimePerFrame = frame_time; + video_format->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + video_format->hdr.bmiHeader.biWidth = format->u.video_mpeg1.width; + video_format->hdr.bmiHeader.biHeight = format->u.video_mpeg1.height; + video_format->hdr.bmiHeader.biPlanes = 1; + video_format->hdr.bmiHeader.biBitCount = 12; + video_format->hdr.bmiHeader.biCompression = mt->subtype.Data1; + video_format->hdr.bmiHeader.biSizeImage = wg_format_get_max_size(format); + + return true; +} + bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) { memset(mt, 0, sizeof(*mt)); @@ -624,6 +665,9 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool
case WG_MAJOR_TYPE_VIDEO_WMV: return amt_from_wg_format_video_wmv(mt, format); + + case WG_MAJOR_TYPE_VIDEO_MPEG1: + return amt_from_wg_format_video_mpeg1(mt, format); }
assert(0); @@ -838,6 +882,30 @@ static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format return true; }
+static bool amt_to_wg_format_video_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_format *format) +{ + const MPEG1VIDEOINFO *video_format = (const MPEG1VIDEOINFO *)mt->pbFormat; + + if (!IsEqualGUID(&mt->formattype, &FORMAT_MPEGVideo)) + { + FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype)); + return false; + } + if (mt->cbFormat < sizeof(VIDEOINFOHEADER) || !mt->pbFormat) + { + ERR("Unexpected format size %lu.\n", mt->cbFormat); + return false; + } + + format->major_type = WG_MAJOR_TYPE_VIDEO_MPEG1; + format->u.video_mpeg1.width = video_format->hdr.bmiHeader.biWidth; + format->u.video_mpeg1.height = video_format->hdr.bmiHeader.biHeight; + format->u.video_mpeg1.fps_n = 10000000; + format->u.video_mpeg1.fps_d = video_format->hdr.AvgTimePerFrame; + + return true; +} + bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) { memset(format, 0, sizeof(*format)); @@ -854,6 +922,8 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV3) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_VC1S)) return amt_to_wg_format_video_wmv(mt, format); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Payload)) + return amt_to_wg_format_video_mpeg1(mt, format); return amt_to_wg_format_video(mt, format); } if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5ae5a7776a8..3ffd6bf927a 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -42,6 +42,7 @@ enum wg_major_type WG_MAJOR_TYPE_VIDEO_H264, WG_MAJOR_TYPE_VIDEO_WMV, WG_MAJOR_TYPE_VIDEO_INDEO, + WG_MAJOR_TYPE_VIDEO_MPEG1, };
typedef UINT32 wg_audio_format; @@ -163,6 +164,11 @@ struct wg_format uint32_t fps_n, fps_d; uint32_t version; } video_indeo; + struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + } video_mpeg1; } u; };
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 2353839bbc4..370c3722f9e 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -282,10 +282,39 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap format->u.video_wmv.fps_d = fps_d; }
+static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint width, height, fps_n, fps_d; + + if (!gst_structure_get_int(structure, "width", &width)) + { + GST_WARNING("Missing "width" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "height", &height)) + { + GST_WARNING("Missing "height" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) + { + fps_n = 0; + fps_d = 1; + } + + format->major_type = WG_MAJOR_TYPE_VIDEO_MPEG1; + format->u.video_mpeg1.width = width; + format->u.video_mpeg1.height = height; + format->u.video_mpeg1.fps_n = fps_n; + format->u.video_mpeg1.fps_d = fps_d; +} + void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); const char *name = gst_structure_get_name(structure); + gboolean parsed;
memset(format, 0, sizeof(*format));
@@ -315,6 +344,10 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { wg_format_from_caps_video_wmv(format, caps); } + else if (!strcmp(name, "video/mpeg") && gst_structure_get_boolean(structure, "parsed", &parsed) && parsed) + { + wg_format_from_caps_video_mpeg1(format, caps); + } else { gchar *str = gst_caps_to_string(caps); @@ -699,6 +732,25 @@ static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format) return caps; }
+static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format) +{ + GstCaps *caps; + + if (!(caps = gst_caps_new_empty_simple("video/mpeg"))) + return NULL; + + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_caps_set_simple(caps, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + gst_caps_set_simple(caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); + if (format->u.video_mpeg1.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_mpeg1.width, NULL); + if (format->u.video_mpeg1.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_mpeg1.height, NULL); + if (format->u.video_mpeg1.fps_d || format->u.video_cinepak.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_mpeg1.fps_n, format->u.video_mpeg1.fps_d, NULL); + return caps; +} + GstCaps *wg_format_to_caps(const struct wg_format *format) { switch (format->major_type) @@ -723,6 +775,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return wg_format_to_caps_video_wmv(format); case WG_MAJOR_TYPE_VIDEO_INDEO: return wg_format_to_caps_video_indeo(format); + case WG_MAJOR_TYPE_VIDEO_MPEG1: + return wg_format_to_caps_video_mpeg1(format); } assert(0); return NULL; @@ -741,6 +795,7 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: + case WG_MAJOR_TYPE_VIDEO_MPEG1: GST_FIXME("Format %u not implemented!", a->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e2b14527a20..5a2dae410bb 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -372,6 +372,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO: case WG_MAJOR_TYPE_VIDEO: break; + case WG_MAJOR_TYPE_VIDEO_MPEG1: case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", input_format.major_type); gst_caps_unref(raw_caps); @@ -425,6 +426,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_MPEG1: GST_FIXME("Format %u not implemented!", output_format.major_type); goto out; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index c8b98c7c769..882b6df1bbb 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1589,6 +1589,8 @@ static const char *get_major_type_string(enum wg_major_type type) return "wmv"; case WG_MAJOR_TYPE_VIDEO_INDEO: return "indeo"; + case WG_MAJOR_TYPE_VIDEO_MPEG1: + return "mpeg1-video"; case WG_MAJOR_TYPE_UNKNOWN: return "unknown"; } @@ -1948,6 +1950,7 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: + case WG_MAJOR_TYPE_VIDEO_MPEG1: FIXME("Format %u not implemented!\n", format.major_type); break; case WG_MAJOR_TYPE_UNKNOWN: @@ -1990,6 +1993,7 @@ static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD o case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: + case WG_MAJOR_TYPE_VIDEO_MPEG1: FIXME("Format %u not implemented!\n", format.major_type); /* fallthrough */ case WG_MAJOR_TYPE_AUDIO: