blob: c382a81803e3c0c6f9125fa6b3b27005a5dacc48 [file] [log] [blame]
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "encoder/win/media_type_dshow.h"
#include <mmreg.h>
#include "encoder/win/media_source_dshow.h"
#include "encoder/win/webm_guids.h"
#include "glog/logging.h"
namespace webmlive {
bool VideoFormatToSubTypeGuid(VideoFormat format, GUID* ptr_sub_type) {
bool converted = false;
if (ptr_sub_type) {
switch (format) {
case kVideoFormatI420:
*ptr_sub_type = MEDIASUBTYPE_I420;
converted = true;
break;
case kVideoFormatVP8:
*ptr_sub_type = MEDIASUBTYPE_VP80;
converted = true;
break;
case kVideoFormatYV12:
*ptr_sub_type = MEDIASUBTYPE_YV12;
converted = true;
break;
case kVideoFormatYUY2:
*ptr_sub_type = MEDIASUBTYPE_YUY2;
converted = true;
break;
case kVideoFormatYUYV:
*ptr_sub_type = MEDIASUBTYPE_YUYV;
converted = true;
break;
case kVideoFormatUYVY:
*ptr_sub_type = MEDIASUBTYPE_UYVY;
converted = true;
break;
case kVideoFormatRGB:
*ptr_sub_type = MEDIASUBTYPE_RGB24;
converted = true;
break;
case kVideoFormatRGBA:
*ptr_sub_type = MEDIASUBTYPE_RGB32;
converted = true;
break;
default:
LOG(WARNING) << "Unknown video format value.";
}
}
return converted;
}
///////////////////////////////////////////////////////////////////////////////
// MediaType
//
MediaType::MediaType(): ptr_type_(NULL) {
}
MediaType::~MediaType() {
FreeMediaType(ptr_type_);
}
// Utility function for cleaning up AM_MEDIA_TYPE and its format blob.
void MediaType::FreeMediaType(AM_MEDIA_TYPE* ptr_media_type) {
if (ptr_media_type) {
FreeMediaTypeData(ptr_media_type);
CoTaskMemFree(ptr_media_type);
}
}
// Utility function for proper clean up of AM_MEDIA_TYPE format blob.
void MediaType::FreeMediaTypeData(AM_MEDIA_TYPE* ptr_media_type) {
if (ptr_media_type) {
if (ptr_media_type->cbFormat != 0) {
// Avoid CoTaskMemFree() on pbFormat within ksproxy.ax based video media
// types. Freeing this memory leads to heap corruption crashes when using
// certain webcams.
if (ptr_media_type->formattype != CLSID_KsDataTypeHandlerVideo)
CoTaskMemFree(ptr_media_type->pbFormat);
ptr_media_type->cbFormat = 0;
ptr_media_type->formattype = GUID_NULL;
ptr_media_type->pbFormat = NULL;
}
if (ptr_media_type->pUnk != NULL) {
// |pUnk| should not be used, but because the Microsoft example code
// has this section, it's included here. (The example also includes the
// note, "pUnk should not be used", but does not explain why cleanup code
// remains in place).
ptr_media_type->pUnk->Release();
ptr_media_type->pUnk = NULL;
}
}
}
// Allocates base AM_MEDIA_TYPE storage. Used by specialized media type classes.
int MediaType::AllocTypeStruct() {
const SIZE_T type_size = sizeof(AM_MEDIA_TYPE);
ptr_type_ = reinterpret_cast<AM_MEDIA_TYPE*>(CoTaskMemAlloc(type_size));
if (!ptr_type_) {
LOG(ERROR) << "AM_MEDIA_TYPE CoTaskMemAlloc returned NULL!";
return kNoMemory;
}
memset(ptr_type_, 0, type_size);
return kSuccess;
}
// Allocates memory for AM_MEDIA_TYPE format blob.
int MediaType::AllocFormatBlob(SIZE_T blob_size) {
if (blob_size == 0) {
LOG(ERROR) << "cannot allocate format blob of size 0.";
return kInvalidArg;
}
if (!ptr_type_) {
LOG(ERROR) << "NULL media type.";
return kNullType;
}
ptr_type_->pbFormat = reinterpret_cast<BYTE*>(CoTaskMemAlloc(blob_size));
if (!ptr_type_->pbFormat) {
LOG(ERROR) << "format blob CoTaskMemAlloc returned NULL!";
return kNoMemory;
}
memset(ptr_type_->pbFormat, 0, blob_size);
ptr_type_->cbFormat = blob_size;
return kSuccess;
}
///////////////////////////////////////////////////////////////////////////////
// VideoMediaType
//
VideoMediaType::VideoMediaType() {
}
VideoMediaType::~VideoMediaType() {
}
// Allocates storage for AM_MEDIA_TYPE struct (|ptr_type_|), and its format
// blob (|ptr_type_->pbFormat|).
int VideoMediaType::Init(const GUID& major_type, const GUID& format_type) {
FreeMediaType(ptr_type_);
if (major_type != MEDIATYPE_Video) {
LOG(ERROR) << "Unsupported major type.";
return kUnsupportedMajorType;
}
if (format_type != FORMAT_VideoInfo && format_type != FORMAT_VideoInfo2) {
LOG(ERROR) << "Unsupported format type.";
return kUnsupportedFormatType;
}
if (AllocTypeStruct()) {
LOG(ERROR) << "AllocTypeStruct failed.";
return kNoMemory;
}
ptr_type_->majortype = major_type;
ptr_type_->formattype = format_type;
// Determine blob size for |format_type|.
const SIZE_T blob_size = (format_type == FORMAT_VideoInfo) ?
sizeof(VIDEOINFOHEADER) : sizeof(VIDEOINFOHEADER2);
// Alloc storage for |format_type|'s format block.
if (AllocFormatBlob(blob_size)) {
LOG(ERROR) << "AllocFormatBlob failed.";
return kNoMemory;
}
return kSuccess;
}
// Copies |media_type| data to |ptr_type_| using |Init| overload to allocate
// storage for |ptr_type_|.
int VideoMediaType::Init(const AM_MEDIA_TYPE& media_type) {
const int status = Init(media_type.majortype, media_type.formattype);
if (status) {
LOG(ERROR) << "Init failed, status=" << status;
return status;
}
*ptr_type_ = media_type;
// TODO(tomfinegan): It might be better to allow override of cbFormat via
// an additional argument to |Init|.
if (ptr_type_->cbFormat != media_type.cbFormat) {
LOG(ERROR) << "AM_MEDIA_TYPE format size mismatch, expected="
<< ptr_type_->cbFormat << " actual=" << media_type.cbFormat
<< ".";
return kUnsupportedFormatType;
}
memcpy(ptr_type_->pbFormat, media_type.pbFormat, ptr_type_->cbFormat);
return kSuccess;
}
// Inits |ptr_type_| with majortype MEDIATYPE_Video and formattype
// FORMAT_VideoInfo. Uses |Init(const GUID&, const GUID&)|.
int VideoMediaType::Init() {
return Init(MEDIATYPE_Video, FORMAT_VideoInfo);
}
int VideoMediaType::ConfigurePartialType(VideoFormat format) {
if (!ptr_type_) {
LOG(ERROR) << "internal AM_MEDIA_TYPE is NULL.";
return kNullType;
}
if (ptr_type_->pbFormat) {
// The |Init()| methods all allocate the format blob and set
// |AM_MEDIA_TYPE::formattype|. Free the blob and set |formattype| to
// GUID_NULL to make a truly partial media type.
FreeMediaTypeData(ptr_type_);
}
int status = kInvalidArg;
GUID subtype = GUID_NULL;
if (VideoFormatToSubTypeGuid(format, &subtype)) {
ptr_type_->subtype = subtype;
status = kSuccess;
}
return status;
}
// Configures AM_MEDIA_TYPE format blob for given |sub_type| and |config|.
int VideoMediaType::ConfigureSubType(VideoFormat sub_type,
const VideoConfig &config) {
// Make sure configuration is sane.
if (config.width <= 0) {
LOG(ERROR) << "Invalid width.";
return kInvalidArg;
}
if (config.height <= 0) {
LOG(ERROR) << "Invalid height.";
return kInvalidArg;
}
if (config.frame_rate <= 0) {
LOG(ERROR) << "Invalid frame rate.";
return kInvalidArg;
}
// Confirm that |sub_type| is supported, and set the temporal compression
// and fixed size samples fields in |ptr_type_|.
switch (sub_type) {
case kVideoFormatVP8:
ptr_type_->bTemporalCompression = TRUE;
ptr_type_->bFixedSizeSamples = FALSE;
break;
case kVideoFormatI420:
case kVideoFormatYV12:
case kVideoFormatYUY2:
case kVideoFormatUYVY:
case kVideoFormatRGB:
case kVideoFormatRGBA:
ptr_type_->bTemporalCompression = FALSE;
ptr_type_->bFixedSizeSamples = TRUE;
break;
default:
LOG(ERROR) << sub_type << " is not a known VideoFormat.";
return kUnsupportedSubType;
}
// Configure the format blobs.
int status = kUnsupportedSubType;
if (ptr_type_->formattype == FORMAT_VideoInfo) {
VIDEOINFOHEADER* ptr_header =
reinterpret_cast<VIDEOINFOHEADER*>(ptr_type_->pbFormat);
status = ConfigureVideoInfoHeader(config, sub_type, ptr_header);
} else if (ptr_type_->formattype ==FORMAT_VideoInfo2) {
VIDEOINFOHEADER2* ptr_header =
reinterpret_cast<VIDEOINFOHEADER2*>(ptr_type_->pbFormat);
status = ConfigureVideoInfoHeader2(config, sub_type, ptr_header);
} else {
LOG(ERROR) << "Unsupported format type.";
}
return status;
}
// Converts |frame_rate| to time per frame, and uses |set_avg_time_per_frame()|
// to apply frame rate to video info header's AvgTimePerFrame member.
int VideoMediaType::set_frame_rate(double frame_rate) {
if (frame_rate <= 0) {
LOG(ERROR) << "invalid frame_rate.";
return kInvalidArg;
}
return set_avg_time_per_frame(seconds_to_media_time(1.0 / frame_rate));
}
// Sets video info header's AvgTimePerFrame member.
int VideoMediaType::set_avg_time_per_frame(REFERENCE_TIME time_per_frame) {
if (time_per_frame <= 0) {
LOG(ERROR) << "invalid time_per_frame.";
return kInvalidArg;
}
if (!ptr_type_) {
LOG(ERROR) << "Null ptr_type_.";
return kNullType;
}
if (ptr_type_->formattype == FORMAT_VideoInfo) {
VIDEOINFOHEADER* ptr_header =
reinterpret_cast<VIDEOINFOHEADER*>(ptr_type_->pbFormat);
ptr_header->AvgTimePerFrame = time_per_frame;
} else if (ptr_type_->formattype == FORMAT_VideoInfo2) {
VIDEOINFOHEADER* ptr_header =
reinterpret_cast<VIDEOINFOHEADER*>(ptr_type_->pbFormat);
ptr_header->AvgTimePerFrame = time_per_frame;
}
return kSuccess;
}
// Calculates frame rate from |avg_time_per_frame()|, and returns it.
double VideoMediaType::frame_rate() const {
double frame_rate = 0.0;
const REFERENCE_TIME time_per_frame = avg_time_per_frame();
if (time_per_frame > 0) {
frame_rate = 1.0 / media_time_to_seconds(time_per_frame);
}
return frame_rate;
}
// Returns time per frame in 100ns ticks.
REFERENCE_TIME VideoMediaType::avg_time_per_frame() const {
REFERENCE_TIME time_per_frame = 0;
if (ptr_type_) {
if (ptr_type_->formattype == FORMAT_VideoInfo) {
const VIDEOINFOHEADER* ptr_header =
reinterpret_cast<const VIDEOINFOHEADER*>(ptr_type_->pbFormat);
time_per_frame = ptr_header->AvgTimePerFrame;
} else if (ptr_type_->formattype == FORMAT_VideoInfo2) {
const VIDEOINFOHEADER* ptr_header =
reinterpret_cast<const VIDEOINFOHEADER*>(ptr_type_->pbFormat);
time_per_frame = ptr_header->AvgTimePerFrame;
}
}
return time_per_frame;
}
// Returns biWidth value from BITMAPINFOHEADER.
int VideoMediaType::width() const {
const BITMAPINFOHEADER* ptr_header = bitmap_header();
int width = 0;
if (ptr_header) {
width = ptr_header->biWidth;
}
return width;
}
// Returns biHeight value from BITMAPINFOHEADER.
int VideoMediaType::height() const {
const BITMAPINFOHEADER* ptr_header = bitmap_header();
int height = 0;
if (ptr_header) {
height = ptr_header->biHeight;
}
return height;
}
// Returns DIBWIDTHBYTES result for BITMAPINFOHEADER.
int VideoMediaType::stride() const {
const BITMAPINFOHEADER* ptr_header = bitmap_header();
int stride = 0;
if (ptr_header) {
stride = DIBWIDTHBYTES(*ptr_header);
}
return stride;
}
// Returns pointer to BITMAPINFOHEADER stored within |ptr_type_|'s format
// blob.
const BITMAPINFOHEADER* VideoMediaType::bitmap_header() const {
if (!ptr_type_ || !ptr_type_->pbFormat) {
LOG(ERROR) << "Null ptr_type_ or format block.";
return NULL;
}
if (ptr_type_->formattype == FORMAT_VideoInfo) {
const VIDEOINFOHEADER* ptr_header =
reinterpret_cast<const VIDEOINFOHEADER*>(ptr_type_->pbFormat);
return &ptr_header->bmiHeader;
} else if (ptr_type_->formattype == FORMAT_VideoInfo2) {
const VIDEOINFOHEADER2* ptr_header =
reinterpret_cast<const VIDEOINFOHEADER2*>(ptr_type_->pbFormat);
return &ptr_header->bmiHeader;
}
return NULL;
}
// Sets AM_MEDIA_TYPE subtype value, and configures BITMAPINFOHEADER using
// values calculated from |sub_type| and |config| entries.
int VideoMediaType::ConfigureFormatInfo(const VideoConfig& config,
VideoFormat sub_type,
BITMAPINFOHEADER& header) {
header.biSize = sizeof header;
header.biHeight = config.height;
header.biWidth = config.width;
header.biPlanes = 1;
switch (sub_type) {
case kVideoFormatI420:
ptr_type_->subtype = MEDIASUBTYPE_I420;
header.biCompression = MAKEFOURCC('I', '4', '2', '0');
header.biBitCount = kI420BitCount;
break;
case kVideoFormatVP8:
ptr_type_->subtype = MEDIASUBTYPE_VP80;
header.biCompression = MAKEFOURCC('V', 'P', '8', '0');
header.biBitCount = 0;
break;
case kVideoFormatYV12:
ptr_type_->subtype = MEDIASUBTYPE_YV12;
header.biCompression = MAKEFOURCC('Y', 'V', '1', '2');
header.biBitCount = kYV12BitCount;
break;
case kVideoFormatYUY2:
ptr_type_->subtype = MEDIASUBTYPE_YUY2;
header.biCompression = MAKEFOURCC('Y', 'U', 'Y', '2');
header.biBitCount = kYUY2BitCount;
break;
case kVideoFormatYUYV:
ptr_type_->subtype = MEDIASUBTYPE_YUYV;
header.biCompression = MAKEFOURCC('Y', 'U', 'Y', 'V');
header.biBitCount = kYUYVBitCount;
break;
case kVideoFormatUYVY:
ptr_type_->subtype = MEDIASUBTYPE_UYVY;
header.biCompression = MAKEFOURCC('U', 'Y', 'V', 'Y');
header.biBitCount = kYUYVBitCount;
break;
case kVideoFormatRGB:
ptr_type_->subtype = MEDIASUBTYPE_RGB24;
header.biCompression = BI_RGB;
header.biBitCount = kRGBBitCount;
break;
case kVideoFormatRGBA:
ptr_type_->subtype = MEDIASUBTYPE_RGB32;
header.biCompression = BI_RGB;
header.biBitCount = kRGBABitCount;
break;
default:
return kUnsupportedSubType;
}
header.biSizeImage = DIBSIZE(header);
return kSuccess;
}
// Zeroes |source| and |target| origin coordinates, sets rectangle right
// value to |config.width| and bottom value to |config.height| to produce
// a video rectangle matching the user's settings.
void VideoMediaType::ConfigureRects(const VideoConfig& config,
RECT& source, RECT& target) {
source.top = source.left = 0;
source.bottom = config.height;
source.right = config.width;
target.top = target.left = 0;
target.bottom = config.height;
target.right = config.width;
}
// Sets video rectangles, frame rate, and returns result of BITMAPINFOHEADER
// configuration attempt.
int VideoMediaType::ConfigureVideoInfoHeader(
const VideoConfig& config,
VideoFormat sub_type,
VIDEOINFOHEADER* ptr_header) {
// Set source and target rectangles.
ConfigureRects(config, ptr_header->rcSource, ptr_header->rcTarget);
if (config.frame_rate != 0) {
// Set frame rate.
ptr_header->AvgTimePerFrame =
seconds_to_media_time(1.0 / config.frame_rate);
}
// Configure BITMAPINFOHEADER.
return ConfigureFormatInfo(config, sub_type, ptr_header->bmiHeader);
}
// Sets video rectangles, frame rate, and returns result of BITMAPINFOHEADER
// configuration attempt.
int VideoMediaType::ConfigureVideoInfoHeader2(
const VideoConfig& config,
VideoFormat sub_type,
VIDEOINFOHEADER2* ptr_header) {
// Set source and target rectangles.
ConfigureRects(config, ptr_header->rcSource, ptr_header->rcTarget);
if (config.frame_rate != 0) {
// Set frame rate.
ptr_header->AvgTimePerFrame =
seconds_to_media_time(1.0 / config.frame_rate);
}
// Configure the BITMAPINFOHEADER.
return ConfigureFormatInfo(config, sub_type, ptr_header->bmiHeader);
}
///////////////////////////////////////////////////////////////////////////////
// AudioMediaType
//
AudioMediaType::AudioMediaType() {
}
AudioMediaType::~AudioMediaType() {
}
// Allocates storage for AM_MEDIA_TYPE struct (|ptr_type_|), and its format
// blob (|ptr_type_->pbFormat|).
int AudioMediaType::Init(const GUID& major_type, const GUID& format_type) {
FreeMediaType(ptr_type_);
if (major_type != MEDIATYPE_Audio) {
LOG(ERROR) << "Unsupported major type.";
return kUnsupportedMajorType;
}
if (format_type != FORMAT_WaveFormatEx) {
LOG(ERROR) << "Unsupported format type.";
return kUnsupportedFormatType;
}
if (AllocTypeStruct()) {
LOG(ERROR) << "AllocTypeStruct failed.";
return kNoMemory;
}
ptr_type_->majortype = major_type;
ptr_type_->formattype = format_type;
ptr_type_->bFixedSizeSamples = TRUE;
ptr_type_->subtype = MEDIASUBTYPE_PCM;
const SIZE_T blob_size = sizeof(WAVEFORMATEX);
// Alloc storage for |format_type|'s format block.
if (AllocFormatBlob(blob_size)) {
LOG(ERROR) << "AllocFormatBlob failed.";
return kNoMemory;
}
WAVEFORMATEX* const ptr_wave_format =
reinterpret_cast<WAVEFORMATEX* const>(ptr_type_->pbFormat);
ptr_wave_format->wFormatTag = WAVE_FORMAT_PCM;
return kSuccess;
}
// Copies |media_type| data to |ptr_type_|.
int AudioMediaType::Init(const AM_MEDIA_TYPE& media_type) {
FreeMediaType(ptr_type_);
if (media_type.majortype != MEDIATYPE_Audio) {
LOG(ERROR) << "Unsupported major type.";
return kUnsupportedMajorType;
}
if (media_type.formattype != FORMAT_WaveFormatEx) {
LOG(ERROR) << "Unsupported format type.";
return kUnsupportedFormatType;
}
if (AllocTypeStruct()) {
LOG(ERROR) << "AllocTypeStruct failed.";
return kNoMemory;
}
memcpy_s(ptr_type_, sizeof(*ptr_type_), &media_type, sizeof(media_type));
if (AllocFormatBlob(media_type.cbFormat)) {
LOG(ERROR) << "AllocFormatBlob failed.";
return kNoMemory;
}
memcpy_s(ptr_type_->pbFormat, ptr_type_->cbFormat, media_type.pbFormat,
media_type.cbFormat);
return kSuccess;
}
int AudioMediaType::Init() {
return Init(MEDIATYPE_Audio, FORMAT_WaveFormatEx);
}
bool AudioMediaType::IsValidWaveFormatExBlob() const {
if (!ptr_type_) {
LOG(ERROR) << "Invalid wave format: null media type.";
return false;
}
if (!ptr_type_->pbFormat) {
LOG(ERROR) << "Invalid wave format: null format blob.";
return false;
}
if (ptr_type_->cbFormat < sizeof(WAVEFORMATEX)) {
LOG(ERROR) << "Invalid wave format: format blob too small.";
return false;
}
return true;
}
bool AudioMediaType::IsValidWaveFormatExtensibleBlob() const {
if (!IsValidWaveFormatExBlob()) {
LOG(ERROR) << "Invalid WAVEFORMATEXTENSIBLE: invalid WAVEFORMATEX.";
return false;
}
if (ptr_type_->cbFormat < sizeof(WAVEFORMATEXTENSIBLE)) {
LOG(ERROR) << "Invalid WAVEFORMATEXTENSIBLE: format blob too small.";
return false;
}
if (format_tag() != WAVE_FORMAT_EXTENSIBLE) {
LOG(ERROR) << "Invalid WAVEFORMATEXTENSIBLE: format tag incorrect.";
return false;
}
return true;
}
int AudioMediaType::Configure(const AudioConfig& config) {
if (!IsValidWaveFormatExBlob()) {
LOG(ERROR) << "invalid format blob.";
return kInvalidFormat;
}
WAVEFORMATEX* const ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
if (!ptr_wave_format) {
LOG(ERROR) << "NULL audio format blob.";
return kUnsupportedFormatType;
}
if (ptr_wave_format->wFormatTag != WAVE_FORMAT_PCM &&
ptr_wave_format->wFormatTag != WAVE_FORMAT_IEEE_FLOAT) {
LOG(ERROR) << "cannot configure, internal type is not PCM or IEEE_FLOAT.";
return kUnsupportedFormatType;
}
const int kBitsPerIeeeFloat = 32;
if (ptr_wave_format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT &&
config.bits_per_sample != kBitsPerIeeeFloat) {
LOG(ERROR) << "cannot configure, sample size incorrect for IEEE_FLOAT.";
return kInvalidFormat;
}
ptr_wave_format->nChannels = config.channels;
ptr_wave_format->nSamplesPerSec = config.sample_rate;
ptr_wave_format->wBitsPerSample = config.bits_per_sample;
const int bytes_per_sample = (ptr_wave_format->wBitsPerSample + 7) / 8;
ptr_wave_format->nAvgBytesPerSec =
config.channels * config.sample_rate * bytes_per_sample;
ptr_wave_format->nBlockAlign =
static_cast<WORD>(bytes_per_sample * config.channels);
ptr_type_->lSampleSize = ptr_wave_format->nBlockAlign;
return kSuccess;
}
uint16 AudioMediaType::block_align() const {
uint16 block_size = 0;
if (IsValidWaveFormatExBlob()) {
const WAVEFORMATEX* ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
block_size = ptr_wave_format->nBlockAlign;
}
return block_size;
}
uint32 AudioMediaType::bytes_per_second() const {
uint32 num_bytes_per_second = 0;
if (IsValidWaveFormatExBlob()) {
const WAVEFORMATEX* ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
num_bytes_per_second = ptr_wave_format->nAvgBytesPerSec;
}
return num_bytes_per_second;
}
uint16 AudioMediaType::channels() const {
uint16 num_channels = 0;
if (IsValidWaveFormatExBlob()) {
const WAVEFORMATEX* ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
num_channels = ptr_wave_format->nChannels;
}
return num_channels;
}
uint16 AudioMediaType::format_tag() const {
uint16 audio_format_tag = 0;
if (IsValidWaveFormatExBlob()) {
const WAVEFORMATEX* ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
audio_format_tag = ptr_wave_format->wFormatTag;
}
return audio_format_tag;
}
uint32 AudioMediaType::sample_rate() const {
uint32 samples_per_second = 0;
if (IsValidWaveFormatExBlob()) {
const WAVEFORMATEX* ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
samples_per_second = ptr_wave_format->nSamplesPerSec;
}
return samples_per_second;
}
uint16 AudioMediaType::bits_per_sample() const {
uint16 num_bits = 0;
if (IsValidWaveFormatExBlob()) {
const WAVEFORMATEX* ptr_wave_format =
reinterpret_cast<WAVEFORMATEX*>(ptr_type_->pbFormat);
num_bits = ptr_wave_format->wBitsPerSample;
}
return num_bits;
}
uint16 AudioMediaType::valid_bits_per_sample() const {
uint16 num_valid_bits = 0;
if (IsValidWaveFormatExtensibleBlob()) {
const WAVEFORMATEXTENSIBLE* ptr_wave_format =
reinterpret_cast<WAVEFORMATEXTENSIBLE*>(ptr_type_->pbFormat);
num_valid_bits = ptr_wave_format->Samples.wValidBitsPerSample;
}
return num_valid_bits;
}
uint16 AudioMediaType::samples_per_block() const {
uint16 num_samples = 0;
if (IsValidWaveFormatExtensibleBlob()) {
const WAVEFORMATEXTENSIBLE* ptr_wave_format =
reinterpret_cast<WAVEFORMATEXTENSIBLE*>(ptr_type_->pbFormat);
num_samples = ptr_wave_format->Samples.wSamplesPerBlock;
}
return num_samples;
}
uint32 AudioMediaType::channel_mask() const {
uint32 channels_present = 0;
if (IsValidWaveFormatExtensibleBlob()) {
const WAVEFORMATEXTENSIBLE* ptr_wave_format =
reinterpret_cast<WAVEFORMATEXTENSIBLE*>(ptr_type_->pbFormat);
channels_present = ptr_wave_format->dwChannelMask;
}
return channels_present;
}
GUID AudioMediaType::sub_format() const {
GUID audio_sub_format = GUID_NULL;
if (IsValidWaveFormatExtensibleBlob()) {
const WAVEFORMATEXTENSIBLE* ptr_wave_format =
reinterpret_cast<WAVEFORMATEXTENSIBLE*>(ptr_type_->pbFormat);
audio_sub_format = ptr_wave_format->SubFormat;
}
return audio_sub_format;
}
///////////////////////////////////////////////////////////////////////////////
// MediaTypePtr
//
MediaTypePtr::MediaTypePtr(): ptr_type_(NULL) {
}
MediaTypePtr::MediaTypePtr(AM_MEDIA_TYPE* ptr_type): ptr_type_(ptr_type) {
}
MediaTypePtr::~MediaTypePtr() {
MediaType::FreeMediaType(ptr_type_);
}
// |Free()|s |ptr_type_| and takes ownership of |ptr_type|. Returns |kSuccess|,
// or |kNullType| if |ptr_type| is NULL.
int MediaTypePtr::Attach(AM_MEDIA_TYPE* ptr_type) {
if (!ptr_type) {
LOG(ERROR) << "NULL media type.";
return kInvalidArg;
}
Free();
ptr_type_ = ptr_type;
return kSuccess;
}
int MediaTypePtr::Copy(const AM_MEDIA_TYPE* ptr_type) {
if (!ptr_type) {
LOG(ERROR) << "NULL media type.";
return kInvalidArg;
}
AM_MEDIA_TYPE* const ptr_copy =
reinterpret_cast<AM_MEDIA_TYPE*>(CoTaskMemAlloc(sizeof AM_MEDIA_TYPE));
if (!ptr_copy) {
LOG(ERROR) << "Cannot alloc media type.";
return kNoMemory;
}
*ptr_copy = *ptr_type;
if (ptr_type->pbFormat) {
ptr_copy->pbFormat =
reinterpret_cast<BYTE*>(CoTaskMemAlloc(ptr_type->cbFormat));
if (!ptr_copy->pbFormat) {
CoTaskMemFree(ptr_copy);
LOG(ERROR) << "Cannot alloc format blob.";
return kNoMemory;
}
memcpy(ptr_copy->pbFormat, ptr_type->pbFormat, ptr_type->cbFormat);
}
return Attach(ptr_copy);
}
void MediaTypePtr::Free() {
MediaType::FreeMediaType(ptr_type_);
ptr_type_ = NULL;
}
// Copies |ptr_type_| and sets it to NULL, then returns the copy.
AM_MEDIA_TYPE* MediaTypePtr::Detach() {
AM_MEDIA_TYPE* ptr_type = ptr_type_;
ptr_type_ = NULL;
return ptr_type;
}
// |Free()|s and returns pointer to |ptr_type_|.
AM_MEDIA_TYPE** MediaTypePtr::GetPtr() {
Free();
return &ptr_type_;
}
} // namespace webmlive