Home | History | Annotate | Download | only in win
      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