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 memset(&requested_capability_, 0, sizeof(requested_capability_)); 24 memset(&resulting_capability_, 0, sizeof(resulting_capability_)); 25 } 26 27 SinkInputPin::~SinkInputPin() {} 28 29 bool SinkInputPin::GetValidMediaType(int index, AM_MEDIA_TYPE* media_type) { 30 if (media_type->cbFormat < sizeof(VIDEOINFOHEADER)) 31 return false; 32 33 VIDEOINFOHEADER* pvi = 34 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); 35 36 ZeroMemory(pvi, sizeof(VIDEOINFOHEADER)); 37 pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 38 pvi->bmiHeader.biPlanes = 1; 39 pvi->bmiHeader.biClrImportant = 0; 40 pvi->bmiHeader.biClrUsed = 0; 41 if (requested_capability_.frame_rate > 0) { 42 pvi->AvgTimePerFrame = kSecondsToReferenceTime / 43 requested_capability_.frame_rate; 44 } 45 46 media_type->majortype = MEDIATYPE_Video; 47 media_type->formattype = FORMAT_VideoInfo; 48 media_type->bTemporalCompression = FALSE; 49 50 switch (index) { 51 case 0: { 52 pvi->bmiHeader.biCompression = MAKEFOURCC('I', '4', '2', '0'); 53 pvi->bmiHeader.biBitCount = 12; // bit per pixel 54 pvi->bmiHeader.biWidth = requested_capability_.width; 55 pvi->bmiHeader.biHeight = requested_capability_.height; 56 pvi->bmiHeader.biSizeImage = 3 * requested_capability_.height * 57 requested_capability_.width / 2; 58 media_type->subtype = kMediaSubTypeI420; 59 break; 60 } 61 case 1: { 62 pvi->bmiHeader.biCompression = MAKEFOURCC('Y', 'U', 'Y', '2'); 63 pvi->bmiHeader.biBitCount = 16; 64 pvi->bmiHeader.biWidth = requested_capability_.width; 65 pvi->bmiHeader.biHeight = requested_capability_.height; 66 pvi->bmiHeader.biSizeImage = 2 * requested_capability_.width * 67 requested_capability_.height; 68 media_type->subtype = MEDIASUBTYPE_YUY2; 69 break; 70 } 71 case 2: { 72 pvi->bmiHeader.biCompression = BI_RGB; 73 pvi->bmiHeader.biBitCount = 24; 74 pvi->bmiHeader.biWidth = requested_capability_.width; 75 pvi->bmiHeader.biHeight = requested_capability_.height; 76 pvi->bmiHeader.biSizeImage = 3 * requested_capability_.height * 77 requested_capability_.width; 78 media_type->subtype = MEDIASUBTYPE_RGB24; 79 break; 80 } 81 default: 82 return false; 83 } 84 85 media_type->bFixedSizeSamples = TRUE; 86 media_type->lSampleSize = pvi->bmiHeader.biSizeImage; 87 return true; 88 } 89 90 bool SinkInputPin::IsMediaTypeValid(const AM_MEDIA_TYPE* media_type) { 91 GUID type = media_type->majortype; 92 if (type != MEDIATYPE_Video) 93 return false; 94 95 GUID format_type = media_type->formattype; 96 if (format_type != FORMAT_VideoInfo) 97 return false; 98 99 // Check for the sub types we support. 100 GUID sub_type = media_type->subtype; 101 VIDEOINFOHEADER* pvi = 102 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); 103 if (pvi == NULL) 104 return false; 105 106 // Store the incoming width and height. 107 resulting_capability_.width = pvi->bmiHeader.biWidth; 108 resulting_capability_.height = abs(pvi->bmiHeader.biHeight); 109 if (pvi->AvgTimePerFrame > 0) { 110 resulting_capability_.frame_rate = 111 static_cast<int>(kSecondsToReferenceTime / pvi->AvgTimePerFrame); 112 } else { 113 resulting_capability_.frame_rate = requested_capability_.frame_rate; 114 } 115 if (sub_type == kMediaSubTypeI420 && 116 pvi->bmiHeader.biCompression == MAKEFOURCC('I', '4', '2', '0')) { 117 resulting_capability_.color = VideoCaptureCapability::kI420; 118 return true; // This format is acceptable. 119 } 120 if (sub_type == MEDIASUBTYPE_YUY2 && 121 pvi->bmiHeader.biCompression == MAKEFOURCC('Y', 'U', 'Y', '2')) { 122 resulting_capability_.color = VideoCaptureCapability::kYUY2; 123 return true; // This format is acceptable. 124 } 125 if (sub_type == MEDIASUBTYPE_RGB24 && 126 pvi->bmiHeader.biCompression == BI_RGB) { 127 resulting_capability_.color = VideoCaptureCapability::kRGB24; 128 return true; // This format is acceptable. 129 } 130 return false; 131 } 132 133 HRESULT SinkInputPin::Receive(IMediaSample* sample) { 134 const int length = sample->GetActualDataLength(); 135 uint8* buffer = NULL; 136 if (FAILED(sample->GetPointer(&buffer))) 137 return S_FALSE; 138 139 observer_->FrameReceived(buffer, length); 140 return S_OK; 141 } 142 143 void SinkInputPin::SetRequestedMediaCapability( 144 const VideoCaptureCapability& capability) { 145 requested_capability_ = capability; 146 resulting_capability_.width = 0; 147 resulting_capability_.height = 0; 148 resulting_capability_.frame_rate = 0; 149 resulting_capability_.color = VideoCaptureCapability::kColorUnknown; 150 resulting_capability_.expected_capture_delay = 0; 151 resulting_capability_.interlaced = false; 152 } 153 154 const VideoCaptureCapability& SinkInputPin::ResultingCapability() { 155 return resulting_capability_; 156 } 157 158 } // namespace media 159