Commit fbf03889 authored by scherkus@chromium.org's avatar scherkus@chromium.org

Remove DemuxerStream::GetAVStream() once and for all.

We now use AudioDecoderConfig and VideoDecoderConfig to pass decoder initialization information.


Review URL: http://codereview.chromium.org/8341033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107494 0039d316-1c4b-4281-b951-d872f2087c98
parent 137e0863
......@@ -8,8 +8,4 @@ namespace media {
DemuxerStream::~DemuxerStream() {}
AVStream* DemuxerStream::GetAVStream() {
return NULL;
}
} // namespace media
......@@ -15,6 +15,7 @@ namespace media {
class AudioDecoderConfig;
class Buffer;
class VideoDecoderConfig;
class MEDIA_EXPORT DemuxerStream
: public base::RefCountedThreadSafe<DemuxerStream> {
......@@ -32,13 +33,14 @@ class MEDIA_EXPORT DemuxerStream
// object takes ownership of the buffer by AddRef()'ing the buffer.
virtual void Read(const ReadCallback& read_callback) = 0;
// Returns an |AVStream*| if supported, or NULL.
virtual AVStream* GetAVStream();
// Returns the audio decoder configuration. It is an error to call this method
// if type() != AUDIO.
virtual const AudioDecoderConfig& audio_decoder_config() = 0;
// Returns the video decoder configuration. It is an error to call this method
// if type() != VIDEO.
virtual const VideoDecoderConfig& video_decoder_config() = 0;
// Returns the type of stream.
virtual Type type() = 0;
......
......@@ -21,6 +21,7 @@
#include "media/base/filters.h"
#include "media/base/filter_collection.h"
#include "media/base/pipeline.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -161,8 +162,8 @@ class MockDemuxerStream : public DemuxerStream {
// DemuxerStream implementation.
MOCK_METHOD0(type, Type());
MOCK_METHOD1(Read, void(const ReadCallback& read_callback));
MOCK_METHOD0(GetAVStream, AVStream*());
MOCK_METHOD0(audio_decoder_config, const AudioDecoderConfig&());
MOCK_METHOD0(video_decoder_config, const VideoDecoderConfig&());
MOCK_METHOD0(EnableBitstreamConverter, void());
protected:
......
......@@ -4,6 +4,8 @@
#include "media/base/video_decoder_config.h"
#include <cmath>
#include "base/logging.h"
namespace media {
......@@ -13,6 +15,8 @@ VideoDecoderConfig::VideoDecoderConfig()
format_(VideoFrame::INVALID),
frame_rate_numerator_(0),
frame_rate_denominator_(0),
aspect_ratio_numerator_(0),
aspect_ratio_denominator_(0),
extra_data_size_(0) {
}
......@@ -22,10 +26,13 @@ VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
const gfx::Rect& visible_rect,
int frame_rate_numerator,
int frame_rate_denominator,
int aspect_ratio_numerator,
int aspect_ratio_denominator,
const uint8* extra_data,
size_t extra_data_size) {
Initialize(codec, format, coded_size, visible_rect,
frame_rate_numerator, frame_rate_denominator,
aspect_ratio_numerator, aspect_ratio_denominator,
extra_data, extra_data_size);
}
......@@ -37,6 +44,8 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
const gfx::Rect& visible_rect,
int frame_rate_numerator,
int frame_rate_denominator,
int aspect_ratio_numerator,
int aspect_ratio_denominator,
const uint8* extra_data,
size_t extra_data_size) {
CHECK((extra_data_size != 0) == (extra_data != NULL));
......@@ -47,6 +56,8 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
visible_rect_ = visible_rect;
frame_rate_numerator_ = frame_rate_numerator;
frame_rate_denominator_ = frame_rate_denominator;
aspect_ratio_numerator_ = aspect_ratio_numerator;
aspect_ratio_denominator_ = aspect_ratio_denominator;
extra_data_size_ = extra_data_size;
if (extra_data_size_ > 0) {
......@@ -55,13 +66,31 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
} else {
extra_data_.reset();
}
// Calculate the natural size given the aspect ratio and visible rect.
if (aspect_ratio_denominator == 0) {
natural_size_.SetSize(0, 0);
return;
}
double aspect_ratio = aspect_ratio_numerator /
static_cast<double>(aspect_ratio_denominator);
int width = floor(visible_rect.width() * aspect_ratio + 0.5);
int height = visible_rect.height();
// An even width makes things easier for YV12 and appears to be the behavior
// expected by WebKit layout tests.
natural_size_.SetSize(width & ~1, height);
}
bool VideoDecoderConfig::IsValidConfig() const {
return codec_ != kUnknownVideoCodec &&
format_ != VideoFrame::INVALID &&
frame_rate_numerator_ > 0 &&
frame_rate_denominator_ > 0;
frame_rate_denominator_ > 0 &&
aspect_ratio_numerator_ > 0 &&
aspect_ratio_denominator_ > 0;
}
VideoCodec VideoDecoderConfig::codec() const {
......@@ -80,6 +109,10 @@ gfx::Rect VideoDecoderConfig::visible_rect() const {
return visible_rect_;
}
gfx::Size VideoDecoderConfig::natural_size() const {
return natural_size_;
}
int VideoDecoderConfig::frame_rate_numerator() const {
return frame_rate_numerator_;
}
......@@ -88,6 +121,14 @@ int VideoDecoderConfig::frame_rate_denominator() const {
return frame_rate_denominator_;
}
int VideoDecoderConfig::aspect_ratio_numerator() const {
return aspect_ratio_numerator_;
}
int VideoDecoderConfig::aspect_ratio_denominator() const {
return aspect_ratio_denominator_;
}
uint8* VideoDecoderConfig::extra_data() const {
return extra_data_.get();
}
......
......@@ -42,6 +42,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
int frame_rate_numerator, int frame_rate_denominator,
int aspect_ratio_numerator, int aspect_ratio_denominator,
const uint8* extra_data, size_t extra_data_size);
~VideoDecoderConfig();
......@@ -52,6 +53,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
int frame_rate_numerator, int frame_rate_denominator,
int aspect_ratio_numerator, int aspect_ratio_denominator,
const uint8* extra_data, size_t extra_data_size);
// Returns true if this object has appropriate configuration values, false
......@@ -70,11 +72,25 @@ class MEDIA_EXPORT VideoDecoderConfig {
// Region of |coded_size_| that is visible.
gfx::Rect visible_rect() const;
// Final visible width and height of a video frame with aspect ratio taken
// into account.
gfx::Size natural_size() const;
// Frame rate in seconds expressed as a fraction.
// TODO(scherkus): fairly certain decoders don't require frame rates.
//
// This information is required to properly timestamp video frames for
// codecs that contain repeated frames, such as found in H.264's
// supplemental enhancement information.
int frame_rate_numerator() const;
int frame_rate_denominator() const;
// Aspect ratio of the decoded video frame expressed as a fraction.
//
// TODO(scherkus): think of a better way to avoid having video decoders
// handle tricky aspect ratio dimension calculations.
int aspect_ratio_numerator() const;
int aspect_ratio_denominator() const;
// Optional byte data required to initialize video decoders, such as H.264
// AAVC data.
uint8* extra_data() const;
......@@ -87,10 +103,14 @@ class MEDIA_EXPORT VideoDecoderConfig {
gfx::Size coded_size_;
gfx::Rect visible_rect_;
gfx::Size natural_size_;
int frame_rate_numerator_;
int frame_rate_denominator_;
int aspect_ratio_numerator_;
int aspect_ratio_denominator_;
scoped_array<uint8> extra_data_;
size_t extra_data_size_;
......
......@@ -83,6 +83,48 @@ static CodecID AudioCodecToCodecID(AudioCodec audio_codec,
return CODEC_ID_NONE;
}
static VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
switch (codec_id) {
case CODEC_ID_VC1:
return kCodecVC1;
case CODEC_ID_H264:
return kCodecH264;
case CODEC_ID_THEORA:
return kCodecTheora;
case CODEC_ID_MPEG2VIDEO:
return kCodecMPEG2;
case CODEC_ID_MPEG4:
return kCodecMPEG4;
case CODEC_ID_VP8:
return kCodecVP8;
default:
NOTREACHED();
}
return kUnknownVideoCodec;
}
static CodecID VideoCodecToCodecID(VideoCodec video_codec) {
switch (video_codec) {
case kUnknownVideoCodec:
return CODEC_ID_NONE;
case kCodecVC1:
return CODEC_ID_VC1;
case kCodecH264:
return CODEC_ID_H264;
case kCodecTheora:
return CODEC_ID_THEORA;
case kCodecMPEG2:
return CODEC_ID_MPEG2VIDEO;
case kCodecMPEG4:
return CODEC_ID_MPEG4;
case kCodecVP8:
return CODEC_ID_VP8;
default:
NOTREACHED();
}
return CODEC_ID_NONE;
}
void AVCodecContextToAudioDecoderConfig(
const AVCodecContext* codec_context,
AudioDecoderConfig* config) {
......@@ -144,46 +186,53 @@ void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
}
}
VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
switch (codec_id) {
case CODEC_ID_VC1:
return kCodecVC1;
case CODEC_ID_H264:
return kCodecH264;
case CODEC_ID_THEORA:
return kCodecTheora;
case CODEC_ID_MPEG2VIDEO:
return kCodecMPEG2;
case CODEC_ID_MPEG4:
return kCodecMPEG4;
case CODEC_ID_VP8:
return kCodecVP8;
default:
NOTREACHED();
}
return kUnknownVideoCodec;
void AVStreamToVideoDecoderConfig(
const AVStream* stream,
VideoDecoderConfig* config) {
gfx::Size coded_size(stream->codec->coded_width, stream->codec->coded_height);
// TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
// for now, but may not always be true forever. Fix this in the future.
gfx::Rect visible_rect(stream->codec->width, stream->codec->height);
AVRational aspect_ratio = { 1, 1 };
if (stream->sample_aspect_ratio.num)
aspect_ratio = stream->sample_aspect_ratio;
else if (stream->codec->sample_aspect_ratio.num)
aspect_ratio = stream->codec->sample_aspect_ratio;
config->Initialize(CodecIDToVideoCodec(stream->codec->codec_id),
PixelFormatToVideoFormat(stream->codec->pix_fmt),
coded_size, visible_rect,
stream->r_frame_rate.num,
stream->r_frame_rate.den,
aspect_ratio.num,
aspect_ratio.den,
stream->codec->extradata,
stream->codec->extradata_size);
}
CodecID VideoCodecToCodecID(VideoCodec video_codec) {
switch (video_codec) {
case kUnknownVideoCodec:
return CODEC_ID_NONE;
case kCodecVC1:
return CODEC_ID_VC1;
case kCodecH264:
return CODEC_ID_H264;
case kCodecTheora:
return CODEC_ID_THEORA;
case kCodecMPEG2:
return CODEC_ID_MPEG2VIDEO;
case kCodecMPEG4:
return CODEC_ID_MPEG4;
case kCodecVP8:
return CODEC_ID_VP8;
default:
NOTREACHED();
void VideoDecoderConfigToAVCodecContext(
const VideoDecoderConfig& config,
AVCodecContext* codec_context) {
codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
codec_context->codec_id = VideoCodecToCodecID(config.codec());
codec_context->coded_width = config.coded_size().width();
codec_context->coded_height = config.coded_size().height();
codec_context->pix_fmt = VideoFormatToPixelFormat(config.format());
if (config.extra_data()) {
codec_context->extradata_size = config.extra_data_size();
codec_context->extradata = reinterpret_cast<uint8_t*>(
av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
memcpy(codec_context->extradata, config.extra_data(),
config.extra_data_size());
memset(codec_context->extradata + config.extra_data_size(), '\0',
FF_INPUT_BUFFER_PADDING_SIZE);
} else {
codec_context->extradata = NULL;
codec_context->extradata_size = 0;
}
return CODEC_ID_NONE;
}
ChannelLayout ChannelLayoutToChromeChannelLayout(int64_t layout,
......@@ -255,27 +304,14 @@ PixelFormat VideoFormatToPixelFormat(VideoFrame::Format video_format) {
return PIX_FMT_NONE;
}
base::TimeDelta GetFrameDuration(AVStream* stream) {
AVRational time_base = { stream->r_frame_rate.den, stream->r_frame_rate.num };
base::TimeDelta GetFrameDuration(const VideoDecoderConfig& config) {
AVRational time_base = {
config.frame_rate_denominator(),
config.frame_rate_numerator()
};
return ConvertFromTimeBase(time_base, 1);
}
gfx::Size GetNaturalSize(AVStream* stream) {
double aspect_ratio = 1.0;
if (stream->sample_aspect_ratio.num)
aspect_ratio = av_q2d(stream->sample_aspect_ratio);
else if (stream->codec->sample_aspect_ratio.num)
aspect_ratio = av_q2d(stream->codec->sample_aspect_ratio);
int height = stream->codec->height;
int width = floor(stream->codec->width * aspect_ratio + 0.5);
// An even width makes things easier for YV12 and appears to be the behavior
// expected by WebKit layout tests.
return gfx::Size(width & ~1, height);
}
void DestroyAVFormatContext(AVFormatContext* format_context) {
DCHECK(format_context);
......
......@@ -74,8 +74,12 @@ void AudioDecoderConfigToAVCodecContext(
const AudioDecoderConfig& config,
AVCodecContext* codec_context);
VideoCodec CodecIDToVideoCodec(CodecID codec_id);
CodecID VideoCodecToCodecID(VideoCodec video_codec);
void AVStreamToVideoDecoderConfig(
const AVStream* stream,
VideoDecoderConfig* config);
void VideoDecoderConfigToAVCodecContext(
const VideoDecoderConfig& config,
AVCodecContext* codec_context);
// Converts FFmpeg's channel layout to chrome's ChannelLayout. |channels| can
// be used when FFmpeg's channel layout is not informative in order to make a
......@@ -89,12 +93,9 @@ VideoFrame::Format PixelFormatToVideoFormat(PixelFormat pixel_format);
// Converts video formats to its corresponding FFmpeg's pixel formats.
PixelFormat VideoFormatToPixelFormat(VideoFrame::Format video_format);
// Calculates duration of one frame in the |stream| based on its frame rate.
base::TimeDelta GetFrameDuration(AVStream* stream);
// Calculates the natural width and height of the video using the video's
// encoded dimensions and sample_aspect_ratio.
gfx::Size GetNaturalSize(AVStream* stream);
// Calculates the duration of one frame based on the frame rate specified by
// |config|.
base::TimeDelta GetFrameDuration(const VideoDecoderConfig& config);
// Closes & destroys all AVStreams in the context and then closes &
// destroys the AVFormatContext.
......
......@@ -29,8 +29,8 @@ namespace media {
// we are making the INFO & TRACKS data look like a small WebM
// file so we can use FFmpeg to initialize the AVFormatContext.
//
// TODO(acolwell): Remove this once GetAVStream() has been removed from
// the DemuxerStream interface.
// TODO(acolwell): Remove this when we construct AudioDecoderConfig and
// VideoDecoderConfig without requiring an AVStream object.
static const uint8 kWebMHeader[] = {
0x1A, 0x45, 0xDF, 0xA3, 0x9F, // EBML (size = 0x1f)
0x42, 0x86, 0x81, 0x01, // EBMLVersion = 1
......@@ -79,13 +79,14 @@ class ChunkDemuxerStream : public DemuxerStream {
virtual void Read(const ReadCallback& read_callback);
virtual Type type();
virtual void EnableBitstreamConverter();
virtual AVStream* GetAVStream();
virtual const AudioDecoderConfig& audio_decoder_config();
virtual const VideoDecoderConfig& video_decoder_config();
private:
Type type_;
AVStream* av_stream_;
AudioDecoderConfig audio_config_;
VideoDecoderConfig video_config_;
mutable base::Lock lock_;
ReadCBQueue read_cbs_;
......@@ -109,6 +110,8 @@ ChunkDemuxerStream::ChunkDemuxerStream(Type type, AVStream* stream)
last_buffer_timestamp_(kNoTimestamp) {
if (type_ == AUDIO) {
AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_);
} else if (type_ == VIDEO) {
AVStreamToVideoDecoderConfig(stream, &video_config_);
}
}
......@@ -271,13 +274,16 @@ DemuxerStream::Type ChunkDemuxerStream::type() { return type_; }
void ChunkDemuxerStream::EnableBitstreamConverter() {}
AVStream* ChunkDemuxerStream::GetAVStream() { return av_stream_; }
const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() {
CHECK_EQ(type_, AUDIO);
return audio_config_;
}
const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() {
CHECK_EQ(type_, VIDEO);
return video_config_;
}
ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
: state_(WAITING_FOR_INIT),
client_(client),
......
......@@ -23,6 +23,11 @@ const AudioDecoderConfig& DummyDemuxerStream::audio_decoder_config() {
return audio_config_;
}
const VideoDecoderConfig& DummyDemuxerStream::video_decoder_config() {
CHECK_EQ(type_, VIDEO);
return video_config_;
}
void DummyDemuxerStream::Read(const ReadCallback& read_callback) {}
void DummyDemuxerStream::EnableBitstreamConverter() {}
......
......@@ -13,6 +13,7 @@
#include "media/base/audio_decoder_config.h"
#include "media/base/demuxer.h"
#include "media/base/video_decoder_config.h"
namespace media {
......@@ -24,6 +25,7 @@ class DummyDemuxerStream : public DemuxerStream {
virtual void Read(const ReadCallback& read_callback) OVERRIDE;
virtual Type type() OVERRIDE;
virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
virtual void EnableBitstreamConverter() OVERRIDE;
private:
......@@ -31,6 +33,7 @@ class DummyDemuxerStream : public DemuxerStream {
Type type_;
AudioDecoderConfig audio_config_;
VideoDecoderConfig video_config_;
DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream);
};
......
......@@ -73,6 +73,7 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
break;
case AVMEDIA_TYPE_VIDEO:
type_ = VIDEO;
AVStreamToVideoDecoderConfig(stream, &video_config_);
break;
default:
NOTREACHED();
......@@ -254,15 +255,16 @@ void FFmpegDemuxerStream::EnableBitstreamConverter() {
}
}
AVStream* FFmpegDemuxerStream::GetAVStream() {
return stream_;
}
const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() {
CHECK_EQ(type_, AUDIO);
return audio_config_;
}
const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() {
CHECK_EQ(type_, VIDEO);
return video_config_;
}
// static
base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp(
const AVRational& time_base, int64 timestamp) {
......@@ -684,8 +686,7 @@ void FFmpegDemuxer::DisableAudioStreamTask() {
// If the codec type is audio, remove the reference. DemuxTask() will
// look for such reference, and this will result in deleting the
// audio packets after they are demuxed.
if (packet_streams_[i]->GetAVStream()->codec->codec_type ==
AVMEDIA_TYPE_AUDIO) {
if (packet_streams_[i]->type() == DemuxerStream::AUDIO) {
packet_streams_[i] = NULL;
}
}
......
......@@ -32,6 +32,7 @@
#include "media/base/buffers.h"
#include "media/base/demuxer.h"
#include "media/base/pipeline.h"
#include "media/base/video_decoder_config.h"
#include "media/filters/ffmpeg_glue.h"
// FFmpeg forward declarations.
......@@ -81,8 +82,8 @@ class FFmpegDemuxerStream : public DemuxerStream {
// |lock_| is held throughout the life of the callback.
virtual void Read(const ReadCallback& read_callback) OVERRIDE;
virtual void EnableBitstreamConverter() OVERRIDE;
virtual AVStream* GetAVStream() OVERRIDE;
virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
private:
virtual ~FFmpegDemuxerStream();
......@@ -102,6 +103,7 @@ class FFmpegDemuxerStream : public DemuxerStream {
FFmpegDemuxer* demuxer_;
AVStream* stream_;
AudioDecoderConfig audio_config_;
VideoDecoderConfig video_config_;
Type type_;
base::TimeDelta duration_;
bool discontinuous_;
......
......@@ -182,22 +182,35 @@ TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
demuxer_->GetStream(DemuxerStream::VIDEO);
ASSERT_TRUE(stream);
EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
ASSERT_TRUE(stream->GetAVStream());
const VideoDecoderConfig& video_config = stream->video_decoder_config();
EXPECT_EQ(kCodecVP8, video_config.codec());
EXPECT_EQ(VideoFrame::YV12, video_config.format());
EXPECT_EQ(320, video_config.coded_size().width());
EXPECT_EQ(240, video_config.coded_size().height());
EXPECT_EQ(0, video_config.visible_rect().x());
EXPECT_EQ(0, video_config.visible_rect().y());
EXPECT_EQ(320, video_config.visible_rect().width());
EXPECT_EQ(240, video_config.visible_rect().height());
EXPECT_EQ(30000, video_config.frame_rate_numerator());
EXPECT_EQ(1001, video_config.frame_rate_denominator());
EXPECT_EQ(1, video_config.aspect_ratio_numerator());
EXPECT_EQ(1, video_config.aspect_ratio_denominator());
EXPECT_FALSE(video_config.extra_data());
EXPECT_EQ(0u, video_config.extra_data_size());
// Audio stream should be present.
stream = demuxer_->GetStream(DemuxerStream::AUDIO);
ASSERT_TRUE(stream);
EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
ASSERT_TRUE(stream->GetAVStream());
// FFmpegDemuxer's audio streams support AudioDecoderConfig structs.
const AudioDecoderConfig& config = stream->audio_decoder_config();
EXPECT_EQ(kCodecVorbis, config.codec());
EXPECT_EQ(16, config.bits_per_channel());
EXPECT_EQ(CHANNEL_LAYOUT_STEREO, config.channel_layout());
EXPECT_EQ(44100, config.samples_per_second());
EXPECT_TRUE(config.extra_data());
EXPECT_GT(config.extra_data_size(), 0u);
const AudioDecoderConfig& audio_config = stream->audio_decoder_config();
EXPECT_EQ(kCodecVorbis, audio_config.codec());
EXPECT_EQ(16, audio_config.bits_per_channel());
EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
EXPECT_EQ(44100, audio_config.samples_per_second());
EXPECT_TRUE(audio_config.extra_data());
EXPECT_GT(audio_config.extra_data_size(), 0u);
}
TEST_F(FFmpegDemuxerTest, Read_Audio) {
......
......@@ -58,22 +58,11 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
initialize_callback_ = callback;
statistics_callback_ = stats_callback;
AVStream* av_stream = demuxer_stream->GetAVStream();
if (!av_stream) {
OnInitializeComplete(false);
return;
}
const VideoDecoderConfig& config = demuxer_stream->video_decoder_config();
pts_stream_.Initialize(GetFrameDuration(av_stream));
pts_stream_.Initialize(GetFrameDuration(config));
gfx::Size coded_size(
av_stream->codec->coded_width, av_stream->codec->coded_height);
// TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
// for now, but may not always be true forever. Fix this in the future.
gfx::Rect visible_rect(
av_stream->codec->width, av_stream->codec->height);
natural_size_ = GetNaturalSize(av_stream);
natural_size_ = config.natural_size();
if (natural_size_.width() > Limits::kMaxDimension ||
natural_size_.height() > Limits::kMaxDimension ||
natural_size_.GetArea() > Limits::kMaxCanvas) {
......@@ -81,14 +70,6 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
return;
}
VideoDecoderConfig config(CodecIDToVideoCodec(av_stream->codec->codec_id),
PixelFormatToVideoFormat(av_stream->codec->pix_fmt),
coded_size, visible_rect,
av_stream->r_frame_rate.num,
av_stream->r_frame_rate.den,
av_stream->codec->extradata,
av_stream->codec->extradata_size);
state_ = kInitializing;
decode_engine_->Initialize(message_loop_, this, NULL, config);
}
......
......@@ -26,6 +26,7 @@ using ::testing::DoAll;
using ::testing::Message;
using ::testing::Return;
using ::testing::ReturnNull;
using ::testing::ReturnRef;
using ::testing::SetArgumentPointee;
using ::testing::StrictMock;
using ::testing::WithArg;
......@@ -33,9 +34,12 @@ using ::testing::Invoke;
namespace media {
static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
static const gfx::Size kCodedSize(1280, 720);
static const gfx::Rect kVisibleRect(1280, 720);
static const gfx::Size kNaturalSize(1280, 720);
static const AVRational kFrameRate = { 100, 1 };
static const AVRational kAspectRatio = { 1, 1 };
// Holds timestamp and duration data needed for properly enqueuing a frame.
struct TimeTuple {
......@@ -134,26 +138,22 @@ class FFmpegVideoDecoderTest : public testing::Test {
demuxer_ = new StrictMock<MockDemuxerStream>();
// Initialize FFmpeg fixtures.
memset(&stream_, 0, sizeof(stream_));
memset(&codec_context_, 0, sizeof(codec_context_));
memset(&codec_, 0, sizeof(codec_));
memset(&yuv_frame_, 0, sizeof(yuv_frame_));
base::TimeDelta zero;
video_frame_ = VideoFrame::CreateFrame(VideoFrame::YV12,
kVisibleRect.width(),
kVisibleRect.height(),
zero, zero);
stream_.codec = &codec_context_;
codec_context_.width = kVisibleRect.width();
codec_context_.height = kVisibleRect.height();
codec_context_.codec_id = CODEC_ID_H264;
stream_.r_frame_rate.num = 1;
stream_.r_frame_rate.den = 1;
buffer_ = new DataBuffer(1);
end_of_stream_buffer_ = new DataBuffer(0);
EXPECT_CALL(stats_callback_object_, OnStatistics(_))
.Times(AnyNumber());
config_.Initialize(kCodecVP8, kVideoFormat, kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
}
virtual ~FFmpegVideoDecoderTest() {
......@@ -170,9 +170,8 @@ class FFmpegVideoDecoderTest : public testing::Test {
}
void InitializeDecoderSuccessfully() {
// Test successful initialization.
EXPECT_CALL(*demuxer_, GetAVStream())
.WillOnce(Return(&stream_));
EXPECT_CALL(*demuxer_, video_decoder_config())
.WillOnce(ReturnRef(config_));
EXPECT_CALL(*engine_, Initialize(_, _, _, _))
.WillOnce(EngineInitialize(engine_, true));
......@@ -199,32 +198,18 @@ class FFmpegVideoDecoderTest : public testing::Test {
MessageLoop message_loop_;
// FFmpeg fixtures.
AVStream stream_;
AVCodecContext codec_context_;
AVCodec codec_;
AVFrame yuv_frame_;
scoped_refptr<VideoFrame> video_frame_;
VideoDecoderConfig config_;
private:
DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
};
TEST_F(FFmpegVideoDecoderTest, Initialize_GetAVStreamFails) {
// Test GetAVStream returning NULL.
EXPECT_CALL(*demuxer_, GetAVStream())
.WillOnce(ReturnNull());
EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
decoder_->Initialize(demuxer_,
NewExpectedClosure(), NewStatisticsCallback());
message_loop_.RunAllPending();
}
TEST_F(FFmpegVideoDecoderTest, Initialize_EngineFails) {
// Test successful initialization.
EXPECT_CALL(*demuxer_, GetAVStream())
.WillOnce(Return(&stream_));
EXPECT_CALL(*demuxer_, video_decoder_config())
.WillOnce(ReturnRef(config_));
EXPECT_CALL(*engine_, Initialize(_, _, _, _))
.WillOnce(EngineInitialize(engine_, false));
......
......@@ -41,6 +41,9 @@ void FFmpegVideoDecodeEngine::Initialize(
VideoDecodeEngine::EventHandler* event_handler,
VideoDecodeContext* context,
const VideoDecoderConfig& config) {
frame_rate_numerator_ = config.frame_rate_numerator();
frame_rate_denominator_ = config.frame_rate_denominator();
// Always try to use three threads for video decoding. There is little reason
// not to since current day CPUs tend to be multi-core and we measured
// performance benefits on older machines such as P4s with hyperthreading.
......@@ -55,24 +58,7 @@ void FFmpegVideoDecodeEngine::Initialize(
// Initialize AVCodecContext structure.
codec_context_ = avcodec_alloc_context();
codec_context_->pix_fmt = VideoFormatToPixelFormat(config.format());
codec_context_->codec_type = AVMEDIA_TYPE_VIDEO;
codec_context_->codec_id = VideoCodecToCodecID(config.codec());
codec_context_->coded_width = config.coded_size().width();
codec_context_->coded_height = config.coded_size().height();
frame_rate_numerator_ = config.frame_rate_numerator();
frame_rate_denominator_ = config.frame_rate_denominator();
if (config.extra_data() != NULL) {
codec_context_->extradata_size = config.extra_data_size();
codec_context_->extradata = reinterpret_cast<uint8_t*>(
av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
memcpy(codec_context_->extradata, config.extra_data(),
config.extra_data_size());
memset(codec_context_->extradata + config.extra_data_size(), '\0',
FF_INPUT_BUFFER_PADDING_SIZE);
}
VideoDecoderConfigToAVCodecContext(config, codec_context_);
// Enable motion vector search (potentially slow), strong deblocking filter
// for damaged macroblocks, and set our error detection sensitivity.
......
......@@ -27,6 +27,7 @@ static const gfx::Size kCodedSize(320, 240);
static const gfx::Rect kVisibleRect(320, 240);
static const gfx::Size kNaturalSize(522, 288);
static const AVRational kFrameRate = { 100, 1 };
static const AVRational kAspectRatio = { 1, 1 };
ACTION_P2(DemuxComplete, engine, buffer) {
engine->ConsumeVideoSample(buffer);
......@@ -38,7 +39,9 @@ class FFmpegVideoDecodeEngineTest
public:
FFmpegVideoDecodeEngineTest()
: config_(kCodecVP8, kVideoFormat, kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den, NULL, 0) {
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0) {
CHECK(FFmpegGlue::GetInstance());
// Setup FFmpeg structures.
......@@ -146,6 +149,7 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) {
VideoDecoderConfig config(kUnknownVideoCodec, kVideoFormat,
kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
// Test avcodec_find_decoder() returning NULL.
......@@ -158,6 +162,7 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) {
VideoDecoderConfig config(kCodecTheora, kVideoFormat,
kCodedSize, kVisibleRect,
kFrameRate.num, kFrameRate.den,
kAspectRatio.num, kAspectRatio.den,
NULL, 0);
EXPECT_CALL(*this, OnInitializeComplete(false));
test_engine_->Initialize(MessageLoop::current(), this, NULL, config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment