Видеозахват выводится всегда в разрешении 320x240, несмотря на изменение разрешения
Хорошо, я был в этом в течение 2 дней и нуждаюсь в помощи с этой последней частью.
У меня есть камера Microsoft LifeCam Cinema, и я использую.NET DirectShowLib для захвата видеопотока. Ну, на самом деле я использую WPFMediaKit, но сейчас я нахожусь в исходном коде того, что касается непосредственно библиотеки прямого показа.
Я работаю так: - Просмотр видео выхода камеры - Запись видео выхода камеры в ASF или AVI (только 2 MediaType поддерживается ICaptureGraphBuilder2)
Проблема в том, что я могу сохранить его как файл.avi. Это работает нормально и с разрешением 1280x720, но сохраняет файл в формате RAW. Это означает, что это около 50-60 МБ в секунду. Слишком высоко.
Или я могу переключиться на.asf, и он выводит WMV, но когда я делаю это, захват и вывод идут в разрешении 320x240.
В WPFMediaKit есть функция, которую я изменил, потому что, очевидно, с камерами Microsoft LifeCam Cinema у многих людей есть эта проблема. Поэтому вместо создания или изменения AMMediaType вы выполняете итерацию, а затем используете ее для вызова SetFormat.
///* Make the VIDEOINFOHEADER 'readable' */
var videoInfo = new VideoInfoHeader();
int iCount = 0, iSize = 0;
videoStreamConfig.GetNumberOfCapabilities(out iCount, out iSize);
IntPtr TaskMemPointer = Marshal.AllocCoTaskMem(iSize);
AMMediaType pmtConfig = null;
for (int iFormat = 0; iFormat < iCount; iFormat++)
{
IntPtr ptr = IntPtr.Zero;
videoStreamConfig.GetStreamCaps(iFormat, out pmtConfig, TaskMemPointer);
videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(pmtConfig.formatPtr, typeof(VideoInfoHeader));
if (videoInfo.BmiHeader.Width == DesiredWidth && videoInfo.BmiHeader.Height == DesiredHeight)
{
///* Setup the VIDEOINFOHEADER with the parameters we want */
videoInfo.AvgTimePerFrame = DSHOW_ONE_SECOND_UNIT / FPS;
if (mediaSubType != Guid.Empty)
{
int fourCC = 0;
byte[] b = mediaSubType.ToByteArray();
fourCC = b[0];
fourCC |= b[1] << 8;
fourCC |= b[2] << 16;
fourCC |= b[3] << 24;
videoInfo.BmiHeader.Compression = fourCC;
// pmtConfig.subType = mediaSubType;
}
/* Copy the data back to unmanaged memory */
Marshal.StructureToPtr(videoInfo, pmtConfig.formatPtr, true);
hr = videoStreamConfig.SetFormat(pmtConfig);
break;
}
}
/* Free memory */
Marshal.FreeCoTaskMem(TaskMemPointer);
DsUtils.FreeAMMediaType(pmtConfig);
if (hr < 0)
return false;
return true;
Когда это было реализовано, я смог наконец просмотреть захваченное видео размером 1280x720, если для SetOutputFilename было установлено значение MediaType.Avi.
Если я установлю его на MediaType.Asf, он идет к 320x240, и вывод такой же.
Или AVI работает и выводит в правильном формате, но делает это в видео RAW, следовательно, очень большой размер файла. Я попытался добавить компрессор к графику, но без удачи, это далеко от моего опыта.
Я ищу 1 из 2 ответов.
- Запись ASF в 1280x720
- Добавление компрессора к графику, чтобы размер моего выходного AVI был небольшим.
2 ответа
Я понял это. Так что я публикую это здесь для любой другой бедной души, которая проходит мимо, удивляясь, почему это не работает.
Загрузите исходный код WPFMediaKit, вам нужно изменить код.
Перейдите в папку DirectShow > MediaPlayers и откройте VideoCapturePlayer.cs
Найдите функцию SetVideoCaptureParameters и замените ее следующим:
/// <summary> /// Sets the capture parameters for the video capture device /// </summary> private bool SetVideoCaptureParameters(ICaptureGraphBuilder2 capGraph, IBaseFilter captureFilter, Guid mediaSubType) { /* The stream config interface */ object streamConfig; /* Get the stream's configuration interface */ int hr = capGraph.FindInterface(PinCategory.Capture, MediaType.Video, captureFilter, typeof(IAMStreamConfig).GUID, out streamConfig); DsError.ThrowExceptionForHR(hr); var videoStreamConfig = streamConfig as IAMStreamConfig; /* If QueryInterface fails... */ if (videoStreamConfig == null) { throw new Exception("Failed to get IAMStreamConfig"); } ///* Make the VIDEOINFOHEADER 'readable' */ var videoInfo = new VideoInfoHeader(); int iCount = 0, iSize = 0; videoStreamConfig.GetNumberOfCapabilities(out iCount, out iSize); IntPtr TaskMemPointer = Marshal.AllocCoTaskMem(iSize); AMMediaType pmtConfig = null; for (int iFormat = 0; iFormat < iCount; iFormat++) { IntPtr ptr = IntPtr.Zero; videoStreamConfig.GetStreamCaps(iFormat, out pmtConfig, TaskMemPointer); videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(pmtConfig.formatPtr, typeof(VideoInfoHeader)); if (videoInfo.BmiHeader.Width == DesiredWidth && videoInfo.BmiHeader.Height == DesiredHeight) { ///* Setup the VIDEOINFOHEADER with the parameters we want */ videoInfo.AvgTimePerFrame = DSHOW_ONE_SECOND_UNIT / FPS; if (mediaSubType != Guid.Empty) { int fourCC = 0; byte[] b = mediaSubType.ToByteArray(); fourCC = b[0]; fourCC |= b[1] << 8; fourCC |= b[2] << 16; fourCC |= b[3] << 24; videoInfo.BmiHeader.Compression = fourCC; // pmtConfig.subType = mediaSubType; } /* Copy the data back to unmanaged memory */ Marshal.StructureToPtr(videoInfo, pmtConfig.formatPtr, true); hr = videoStreamConfig.SetFormat(pmtConfig); break; } } /* Free memory */ Marshal.FreeCoTaskMem(TaskMemPointer); DsUtils.FreeAMMediaType(pmtConfig); if (hr < 0) return false; return true; }
Теперь это отсортирует экран на любом желаемом разрешении, которое вы хотите, при условии, что ваша камера поддерживает его.
Затем вы скоро поймете, что этот новый правильный захват не применяется при записи видео на диск.
Так как метод ICaptureBuilder2 поддерживает только Avi и Asf (то есть wmv), вам нужно установить свой тип обращения к одному из них.
hr = graphBuilder.SetOutputFileName(MediaSubType.Asf, this.m_fileName, out mux, out sink);
Вы найдете эту строку в функции SetupGraph.
Asf будет выводить только в формате 320x240, но Avi будет выводить его в желаемом разрешении, но без сжатия (то есть 50-60 МБ в секунду для видеопотока 1280x720), что слишком высоко.
Так что остается 2 варианта
Узнайте, как добавить кодировщик (фильтр сжатия) к выходу Avi
Выясните, как изменить профиль WMV
Я попробовал 1, но безуспешно. Главным образом из-за того, что я впервые работаю с DirectShow и только понимаю смысл графиков.
Но я был успешен с #2, и вот как я это сделал.
Особая благодарность (http://www.codeproject.com/KB/audio-video/videosav.aspx) я вытащил отсюда необходимый код.
- Создайте новый класс в той же папке с именем WMLib.cs и поместите в него следующее
Загрузите демонстрационный проект с http://www.codeproject.com/KB/audio-video/videosav.aspx скопируйте и вставьте файл WMLib.cs в свой проект (при необходимости измените пространство имен).
Создайте функцию в классе VideoCapturePlayer.cs
/// <summary> /// Configure profile from file to Asf file writer /// </summary> /// <param name="asfWriter"></param> /// <param name="filename"></param> /// <returns></returns> public bool ConfigProfileFromFile(IBaseFilter asfWriter, string filename) { int hr; //string profilePath = "test.prx"; // Set the profile to be used for conversion if ((filename != null) && (File.Exists(filename))) { // Load the profile XML contents string profileData; using (StreamReader reader = new StreamReader(File.OpenRead(filename))) { profileData = reader.ReadToEnd(); } // Create an appropriate IWMProfile from the data // Open the profile manager IWMProfileManager profileManager; IWMProfile wmProfile = null; hr = WMLib.WMCreateProfileManager(out profileManager); if (hr >= 0) { // error message: The profile is invalid (0xC00D0BC6) // E.g. no <prx> tags hr = profileManager.LoadProfileByData(profileData, out wmProfile); } if (profileManager != null) { Marshal.ReleaseComObject(profileManager); profileManager = null; } // Config only if there is a profile retrieved if (hr >= 0) { // Set the profile on the writer IConfigAsfWriter configWriter = (IConfigAsfWriter)asfWriter; hr = configWriter.ConfigureFilterUsingProfile(wmProfile); if (hr >= 0) { return true; } } } return false; }
В функции SetupGraph найдите SetOutputFileName и под ним поставьте
ConfigProfileFromFile(mux, "c:\wmv.prx");
Теперь создайте файл с именем wmv.prx на вашем диске c: и поместите в него соответствующую информацию.
Вы можете увидеть образец файла PRX из демонстрационного проекта здесь: http://www.codeproject.com/KB/audio-video/videosav.aspx (Pal90.prx)
А теперь наслаждайтесь вашим файлом.wmv, выведенным в правильном размере. Да, я знаю, что код, который я поместил, был довольно неаккуратным, но я оставлю его на ваше усмотрение.
Lifecam известна неочевидным поведением при настройке формата захвата (точнее, обращаясь к другим форматам). Смотрите предварительные обсуждения, которые могут предложить вам решение: