1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/video/capture/win/sink_input_pin_win.h" 6 7 #include <cstring> 8 9 // Avoid including strsafe.h via dshow as it will cause build warnings. 10 #define NO_DSHOW_STRSAFE 11 #include <dshow.h> 12 13 #include "base/logging.h" 14 15 namespace media { 16 17 const REFERENCE_TIME kSecondsToReferenceTime = 10000000; 18 19 SinkInputPin::SinkInputPin(IBaseFilter* filter, 20 SinkFilterObserver* observer) 21 : observer_(observer), 22 PinBase(filter) { 23 } 24 25 SinkInputPin::~SinkInputPin() {} 26 27 bool SinkInputPin::GetValidMediaType(int index, AM_MEDIA_TYPE* media_type) { 28 if (media_type->cbFormat < sizeof(VIDEOINFOHEADER)) 29 return false; 30 31 VIDEOINFOHEADER* pvi = 32 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); 33 34 ZeroMemory(pvi, sizeof(VIDEOINFOHEADER)); 35 pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 36 pvi->bmiHeader.biPlanes = 1; 37 pvi->bmiHeader.biClrImportant = 0; 38 pvi->bmiHeader.biClrUsed = 0; 39 if (requested_format_.frame_rate > 0) { 40 pvi->AvgTimePerFrame = 41 kSecondsToReferenceTime / requested_format_.frame_rate; 42 } 43 44 media_type->majortype = MEDIATYPE_Video; 45 media_type->formattype = FORMAT_VideoInfo; 46 media_type->bTemporalCompression = FALSE; 47 48 switch (index) { 49 case 0: { 50 pvi->bmiHeader.biCompression = MAKEFOURCC('I', '4', '2', '0'); 51 pvi->bmiHeader.biBitCount = 12; // bit per pixel 52 pvi->bmiHeader.biWidth = requested_format_.frame_size.width(); 53 pvi->bmiHeader.biHeight = requested_format_.frame_size.height(); 54 pvi->bmiHeader.biSizeImage = 55 requested_format_.frame_size.GetArea() * 3 / 2; 56 media_type->subtype = kMediaSubTypeI420; 57 break; 58 } 59 case 1: { 60 pvi->bmiHeader.biCompression = MAKEFOURCC('Y', 'U', 'Y', '2'); 61 pvi->bmiHeader.biBitCount = 16; 62 pvi->bmiHeader.biWidth = requested_format_.frame_size.width(); 63 pvi->bmiHeader.biHeight = requested_format_.frame_size.height(); 64 pvi->bmiHeader.biSizeImage = requested_format_.frame_size.GetArea() * 2; 65 media_type->subtype = MEDIASUBTYPE_YUY2; 66 break; 67 } 68 case 2: { 69 pvi->bmiHeader.biCompression = BI_RGB; 70 pvi->bmiHeader.biBitCount = 24; 71 pvi->bmiHeader.biWidth = requested_format_.frame_size.width(); 72 pvi->bmiHeader.biHeight = requested_format_.frame_size.height(); 73 pvi->bmiHeader.biSizeImage = requested_format_.frame_size.GetArea() * 3; 74 media_type->subtype = MEDIASUBTYPE_RGB24; 75 break; 76 } 77 default: 78 return false; 79 } 80 81 media_type->bFixedSizeSamples = TRUE; 82 media_type->lSampleSize = pvi->bmiHeader.biSizeImage; 83 return true; 84 } 85 86 bool SinkInputPin::IsMediaTypeValid(const AM_MEDIA_TYPE* media_type) { 87 GUID type = media_type->majortype; 88 if (type != MEDIATYPE_Video) 89 return false; 90 91 GUID format_type = media_type->formattype; 92 if (format_type != FORMAT_VideoInfo) 93 return false; 94 95 // Check for the sub types we support. 96 GUID sub_type = media_type->subtype; 97 VIDEOINFOHEADER* pvi = 98 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); 99 if (pvi == NULL) 100 return false; 101 102 // Store the incoming width and height. 103 resulting_format_.frame_size.SetSize(pvi->bmiHeader.biWidth, 104 abs(pvi->bmiHeader.biHeight)); 105 if (pvi->AvgTimePerFrame > 0) { 106 resulting_format_.frame_rate = 107 static_cast<int>(kSecondsToReferenceTime / pvi->AvgTimePerFrame); 108 } else { 109 resulting_format_.frame_rate = requested_format_.frame_rate; 110 } 111 if (sub_type == kMediaSubTypeI420 && 112 pvi->bmiHeader.biCompression == MAKEFOURCC('I', '4', '2', '0')) { 113 resulting_format_.pixel_format = PIXEL_FORMAT_I420; 114 return true; // This format is acceptable. 115 } 116 if (sub_type == MEDIASUBTYPE_YUY2 && 117 pvi->bmiHeader.biCompression == MAKEFOURCC('Y', 'U', 'Y', '2')) { 118 resulting_format_.pixel_format = PIXEL_FORMAT_YUY2; 119 return true; // This format is acceptable. 120 } 121 if (sub_type == MEDIASUBTYPE_RGB24 && 122 pvi->bmiHeader.biCompression == BI_RGB) { 123 resulting_format_.pixel_format = PIXEL_FORMAT_RGB24; 124 return true; // This format is acceptable. 125 } 126 return false; 127 } 128 129 HRESULT SinkInputPin::Receive(IMediaSample* sample) { 130 const int length = sample->GetActualDataLength(); 131 uint8* buffer = NULL; 132 if (FAILED(sample->GetPointer(&buffer))) 133 return S_FALSE; 134 135 observer_->FrameReceived(buffer, length); 136 return S_OK; 137 } 138 139 void SinkInputPin::SetRequestedMediaFormat(const VideoCaptureFormat& format) { 140 requested_format_ = format; 141 resulting_format_.frame_size.SetSize(0, 0); 142 resulting_format_.frame_rate = 0; 143 resulting_format_.pixel_format = PIXEL_FORMAT_UNKNOWN; 144 } 145 146 const VideoCaptureFormat& SinkInputPin::ResultingFormat() { 147 return resulting_format_; 148 } 149 150 } // namespace media 151