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
SinkInputPin(IBaseFilter * filter,SinkFilterObserver * observer)19 SinkInputPin::SinkInputPin(IBaseFilter* filter,
20 SinkFilterObserver* observer)
21 : observer_(observer),
22 PinBase(filter) {
23 }
24
~SinkInputPin()25 SinkInputPin::~SinkInputPin() {}
26
GetValidMediaType(int index,AM_MEDIA_TYPE * media_type)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
IsMediaTypeValid(const AM_MEDIA_TYPE * media_type)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
Receive(IMediaSample * sample)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
SetRequestedMediaFormat(const VideoCaptureFormat & format)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
ResultingFormat()146 const VideoCaptureFormat& SinkInputPin::ResultingFormat() {
147 return resulting_format_;
148 }
149
150 } // namespace media
151