OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // ffmpeg_unittests verify that the parts of the FFmpeg API that Chromium uses | 5 // ffmpeg_unittests verify that the parts of the FFmpeg API that Chromium uses |
6 // function as advertised for each media format that Chromium supports. This | 6 // function as advertised for each media format that Chromium supports. This |
7 // mostly includes stuff like reporting proper timestamps, seeking to | 7 // mostly includes stuff like reporting proper timestamps, seeking to |
8 // keyframes, and supporting certain features like reordered_opaque. | 8 // keyframes, and supporting certain features like reordered_opaque. |
9 // | 9 // |
10 // Known failures as of r54591: | 10 // Known failures as of r54591: |
(...skipping 28 matching lines...) Expand all Loading... |
39 #include "media/ffmpeg/ffmpeg_common.h" | 39 #include "media/ffmpeg/ffmpeg_common.h" |
40 #include "media/ffmpeg/file_protocol.h" | 40 #include "media/ffmpeg/file_protocol.h" |
41 #include "testing/gtest/include/gtest/gtest.h" | 41 #include "testing/gtest/include/gtest/gtest.h" |
42 | 42 |
43 int main(int argc, char** argv) { | 43 int main(int argc, char** argv) { |
44 return base::PerfTestSuite(argc, argv).Run(); | 44 return base::PerfTestSuite(argc, argv).Run(); |
45 } | 45 } |
46 | 46 |
47 namespace media { | 47 namespace media { |
48 | 48 |
| 49 // Mirror setting in ffmpeg_video_decoder. |
| 50 static const int kDecodeThreads = 2; |
| 51 |
49 class AVPacketQueue { | 52 class AVPacketQueue { |
50 public: | 53 public: |
51 AVPacketQueue() { | 54 AVPacketQueue() { |
52 } | 55 } |
53 | 56 |
54 ~AVPacketQueue() { | 57 ~AVPacketQueue() { |
55 flush(); | 58 flush(); |
56 } | 59 } |
57 | 60 |
58 bool empty() { | 61 bool empty() { |
(...skipping 21 matching lines...) Expand all Loading... |
80 pop(); | 83 pop(); |
81 } | 84 } |
82 } | 85 } |
83 | 86 |
84 private: | 87 private: |
85 std::queue<AVPacket*> packets_; | 88 std::queue<AVPacket*> packets_; |
86 | 89 |
87 DISALLOW_COPY_AND_ASSIGN(AVPacketQueue); | 90 DISALLOW_COPY_AND_ASSIGN(AVPacketQueue); |
88 }; | 91 }; |
89 | 92 |
| 93 // TODO(dalecurtis): We should really just use PipelineIntegrationTests instead |
| 94 // of a one-off step decoder so we're exercising the real pipeline. |
90 class FFmpegTest : public testing::TestWithParam<const char*> { | 95 class FFmpegTest : public testing::TestWithParam<const char*> { |
91 protected: | 96 protected: |
92 FFmpegTest() | 97 FFmpegTest() |
93 : av_format_context_(NULL), | 98 : av_format_context_(NULL), |
94 audio_stream_index_(-1), | 99 audio_stream_index_(-1), |
95 video_stream_index_(-1), | 100 video_stream_index_(-1), |
96 audio_buffer_(NULL), | 101 audio_buffer_(NULL), |
97 video_buffer_(NULL), | 102 video_buffer_(NULL), |
98 decoded_audio_time_(AV_NOPTS_VALUE), | 103 decoded_audio_time_(AV_NOPTS_VALUE), |
99 decoded_audio_duration_(AV_NOPTS_VALUE), | 104 decoded_audio_duration_(AV_NOPTS_VALUE), |
(...skipping 26 matching lines...) Expand all Loading... |
126 .AppendASCII(name.c_str()); | 131 .AppendASCII(name.c_str()); |
127 FilePath::StringType raw_path = path.value(); | 132 FilePath::StringType raw_path = path.value(); |
128 EXPECT_TRUE(file_util::PathExists(path)); | 133 EXPECT_TRUE(file_util::PathExists(path)); |
129 | 134 |
130 #if defined(OS_WIN) | 135 #if defined(OS_WIN) |
131 std::string ascii_path = WideToASCII(path.value()); | 136 std::string ascii_path = WideToASCII(path.value()); |
132 #else | 137 #else |
133 std::string ascii_path = path.value(); | 138 std::string ascii_path = path.value(); |
134 #endif | 139 #endif |
135 | 140 |
136 EXPECT_EQ(0, av_open_input_file(&av_format_context_, | 141 EXPECT_EQ(0, avformat_open_input(&av_format_context_, |
137 ascii_path.c_str(), | 142 ascii_path.c_str(), |
138 NULL, 0, NULL)) | 143 NULL, NULL)) |
139 << "Could not open " << path.value(); | 144 << "Could not open " << path.value(); |
140 EXPECT_LE(0, av_find_stream_info(av_format_context_)) | 145 EXPECT_LE(0, avformat_find_stream_info(av_format_context_, NULL)) |
141 << "Could not find stream information for " << path.value(); | 146 << "Could not find stream information for " << path.value(); |
142 | 147 |
143 // Determine duration by picking max stream duration. | 148 // Determine duration by picking max stream duration. |
144 for (unsigned int i = 0; i < av_format_context_->nb_streams; ++i) { | 149 for (unsigned int i = 0; i < av_format_context_->nb_streams; ++i) { |
145 AVStream* av_stream = av_format_context_->streams[i]; | 150 AVStream* av_stream = av_format_context_->streams[i]; |
146 int64 duration = ConvertFromTimeBase(av_stream->time_base, | 151 int64 duration = ConvertFromTimeBase( |
147 av_stream->duration).InMicroseconds(); | 152 av_stream->time_base, av_stream->duration).InMicroseconds(); |
148 duration_ = std::max(duration_, duration); | 153 duration_ = std::max(duration_, duration); |
149 } | 154 } |
150 | 155 |
151 // Final check to see if the container itself specifies a duration. | 156 // Final check to see if the container itself specifies a duration. |
152 AVRational av_time_base = {1, AV_TIME_BASE}; | 157 AVRational av_time_base = {1, AV_TIME_BASE}; |
153 int64 duration = | 158 int64 duration = |
154 ConvertFromTimeBase(av_time_base, | 159 ConvertFromTimeBase(av_time_base, |
155 av_format_context_->duration).InMicroseconds(); | 160 av_format_context_->duration).InMicroseconds(); |
156 duration_ = std::max(duration_, duration); | 161 duration_ = std::max(duration_, duration); |
157 } | 162 } |
158 | 163 |
159 void CloseFile() { | 164 void CloseFile() { |
160 av_close_input_file(av_format_context_); | 165 avformat_close_input(&av_format_context_); |
161 } | 166 } |
162 | 167 |
163 void OpenCodecs() { | 168 void OpenCodecs() { |
164 for (unsigned int i = 0; i < av_format_context_->nb_streams; ++i) { | 169 for (unsigned int i = 0; i < av_format_context_->nb_streams; ++i) { |
165 AVStream* av_stream = av_format_context_->streams[i]; | 170 AVStream* av_stream = av_format_context_->streams[i]; |
166 AVCodecContext* av_codec_context = av_stream->codec; | 171 AVCodecContext* av_codec_context = av_stream->codec; |
167 AVCodec* av_codec = avcodec_find_decoder(av_codec_context->codec_id); | 172 AVCodec* av_codec = avcodec_find_decoder(av_codec_context->codec_id); |
168 | 173 |
169 EXPECT_TRUE(av_codec) | 174 EXPECT_TRUE(av_codec) |
170 << "Could not find AVCodec with CodecID " | 175 << "Could not find AVCodec with CodecID " |
171 << av_codec_context->codec_id; | 176 << av_codec_context->codec_id; |
172 EXPECT_EQ(0, avcodec_open(av_codec_context, av_codec)) | 177 |
| 178 av_codec_context->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; |
| 179 av_codec_context->err_recognition = AV_EF_CAREFUL; |
| 180 av_codec_context->thread_count = ( |
| 181 av_codec_context->codec_id == CODEC_ID_THEORA ? 1 : kDecodeThreads); |
| 182 |
| 183 EXPECT_EQ(0, avcodec_open2(av_codec_context, av_codec, NULL)) |
173 << "Could not open AVCodecContext with CodecID " | 184 << "Could not open AVCodecContext with CodecID " |
174 << av_codec_context->codec_id; | 185 << av_codec_context->codec_id; |
175 | 186 |
176 if (av_codec->type == AVMEDIA_TYPE_AUDIO) { | 187 if (av_codec->type == AVMEDIA_TYPE_AUDIO) { |
177 EXPECT_EQ(-1, audio_stream_index_) << "Found multiple audio streams."; | 188 EXPECT_EQ(-1, audio_stream_index_) << "Found multiple audio streams."; |
178 audio_stream_index_ = static_cast<int>(i); | 189 audio_stream_index_ = static_cast<int>(i); |
179 } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) { | 190 } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) { |
180 EXPECT_EQ(-1, video_stream_index_) << "Found multiple video streams."; | 191 EXPECT_EQ(-1, video_stream_index_) << "Found multiple video streams."; |
181 video_stream_index_ = static_cast<int>(i); | 192 video_stream_index_ = static_cast<int>(i); |
182 } else { | 193 } else { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 } | 275 } |
265 | 276 |
266 EXPECT_GE(result, 0) << "Audio decode error."; | 277 EXPECT_GE(result, 0) << "Audio decode error."; |
267 if (result < 0 || (size_out == 0 && end_of_stream)) { | 278 if (result < 0 || (size_out == 0 && end_of_stream)) { |
268 return false; | 279 return false; |
269 } | 280 } |
270 | 281 |
271 if (result > 0) { | 282 if (result > 0) { |
272 // TODO(scherkus): move this to ffmpeg_common.h and dedup. | 283 // TODO(scherkus): move this to ffmpeg_common.h and dedup. |
273 int64 denominator = av_audio_context()->channels * | 284 int64 denominator = av_audio_context()->channels * |
274 av_get_bits_per_sample_fmt(av_audio_context()->sample_fmt) / 8 * | 285 av_get_bytes_per_sample(av_audio_context()->sample_fmt) * |
275 av_audio_context()->sample_rate; | 286 av_audio_context()->sample_rate; |
276 double microseconds = size_out / | 287 double microseconds = size_out / |
277 (denominator / | 288 (denominator / |
278 static_cast<double>(base::Time::kMicrosecondsPerSecond)); | 289 static_cast<double>(base::Time::kMicrosecondsPerSecond)); |
279 decoded_audio_duration_ = static_cast<int64>(microseconds); | 290 decoded_audio_duration_ = static_cast<int64>(microseconds); |
280 | 291 |
281 if (packet.pts == static_cast<int64>(AV_NOPTS_VALUE)) { | 292 if (packet.pts == static_cast<int64>(AV_NOPTS_VALUE)) { |
282 EXPECT_NE(decoded_audio_time_, static_cast<int64>(AV_NOPTS_VALUE)) | 293 EXPECT_NE(decoded_audio_time_, static_cast<int64>(AV_NOPTS_VALUE)) |
283 << "We never received an initial timestamped audio packet! " | 294 << "We never received an initial timestamped audio packet! " |
284 << "Looks like there's a seeking/parsing bug in FFmpeg."; | 295 << "Looks like there's a seeking/parsing bug in FFmpeg."; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 static bool initialized = false; | 406 static bool initialized = false; |
396 if (initialized) { | 407 if (initialized) { |
397 return; | 408 return; |
398 } | 409 } |
399 | 410 |
400 FilePath path; | 411 FilePath path; |
401 PathService::Get(base::DIR_MODULE, &path); | 412 PathService::Get(base::DIR_MODULE, &path); |
402 EXPECT_TRUE(InitializeMediaLibrary(path)) | 413 EXPECT_TRUE(InitializeMediaLibrary(path)) |
403 << "Could not initialize media library."; | 414 << "Could not initialize media library."; |
404 | 415 |
405 avcodec_init(); | |
406 av_log_set_level(AV_LOG_FATAL); | 416 av_log_set_level(AV_LOG_FATAL); |
407 av_register_all(); | 417 av_register_all(); |
408 av_register_protocol2(&kFFmpegFileProtocol, sizeof(kFFmpegFileProtocol)); | 418 ffurl_register_protocol(&kFFmpegFileProtocol, sizeof(kFFmpegFileProtocol)); |
409 initialized = true; | 419 initialized = true; |
410 } | 420 } |
411 | 421 |
412 AVFormatContext* av_format_context_; | 422 AVFormatContext* av_format_context_; |
413 int audio_stream_index_; | 423 int audio_stream_index_; |
414 int video_stream_index_; | 424 int video_stream_index_; |
415 AVPacketQueue audio_packets_; | 425 AVPacketQueue audio_packets_; |
416 AVPacketQueue video_packets_; | 426 AVPacketQueue video_packets_; |
417 | 427 |
418 scoped_ptr_malloc<int16, media::ScopedPtrAVFree> audio_buffer_; | 428 scoped_ptr_malloc<int16, media::ScopedPtrAVFree> audio_buffer_; |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 SeekTo(0.4); | 656 SeekTo(0.4); |
647 ReadRemainingFile(); | 657 ReadRemainingFile(); |
648 EXPECT_TRUE(StepDecodeVideo()); | 658 EXPECT_TRUE(StepDecodeVideo()); |
649 VLOG(1) << decoded_video_time(); | 659 VLOG(1) << decoded_video_time(); |
650 | 660 |
651 CloseCodecs(); | 661 CloseCodecs(); |
652 CloseFile(); | 662 CloseFile(); |
653 } | 663 } |
654 | 664 |
655 } // namespace media | 665 } // namespace media |
OLD | NEW |