blob: de0e7ab253aec418ea6715558cc76a9a138cca22 [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/file_path.h"
#include "base/memory/ref_counted.h"
#include "cobalt/base/wrap_main.h"
#include "cobalt/media/sandbox/fuzzer_app.h"
#include "cobalt/media/sandbox/in_memory_data_source.h"
#include "cobalt/media/sandbox/media_sandbox.h"
#include "media/base/bind_to_loop.h"
#include "media/base/pipeline_status.h"
#include "media/filters/shell_demuxer.h"
namespace cobalt {
namespace media {
namespace sandbox {
namespace {
using base::Bind;
using ::media::BindToCurrentLoop;
using ::media::DecoderBuffer;
using ::media::Demuxer;
using ::media::DemuxerHost;
using ::media::DemuxerStream;
using ::media::PipelineStatus;
using ::media::ShellDemuxer;
class ShellDemuxerFuzzer : DemuxerHost {
public:
explicit ShellDemuxerFuzzer(const std::vector<uint8>& content)
: error_occurred_(false), eos_count_(0), stopped_(false) {
demuxer_ = new ShellDemuxer(base::MessageLoopProxy::current(),
new InMemoryDataSource(content));
}
void Fuzz() {
demuxer_->Initialize(
this, Bind(&ShellDemuxerFuzzer::InitializeCB, base::Unretained(this)));
// Check if there is any error or if both of the audio and video streams
// have reached eos.
while (!error_occurred_ && eos_count_ != 2) {
MessageLoop::current()->RunUntilIdle();
}
demuxer_->Stop(Bind(&ShellDemuxerFuzzer::StopCB, base::Unretained(this)));
while (!stopped_) {
MessageLoop::current()->RunUntilIdle();
}
}
private:
// DataSourceHost methods (parent class of DemuxerHost)
void SetTotalBytes(int64 total_bytes) OVERRIDE {
UNREFERENCED_PARAMETER(total_bytes);
}
void AddBufferedByteRange(int64 start, int64 end) OVERRIDE {
UNREFERENCED_PARAMETER(start);
UNREFERENCED_PARAMETER(end);
}
void AddBufferedTimeRange(base::TimeDelta start,
base::TimeDelta end) OVERRIDE {
UNREFERENCED_PARAMETER(start);
UNREFERENCED_PARAMETER(end);
}
// DemuxerHost methods
void SetDuration(base::TimeDelta duration) OVERRIDE {
UNREFERENCED_PARAMETER(duration);
}
void OnDemuxerError(PipelineStatus error) OVERRIDE {
UNREFERENCED_PARAMETER(error);
error_occurred_ = true;
}
void InitializeCB(PipelineStatus status) {
DCHECK(!error_occurred_);
if (status != ::media::PIPELINE_OK) {
error_occurred_ = true;
return;
}
scoped_refptr<DemuxerStream> audio_stream =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStream> video_stream =
demuxer_->GetStream(DemuxerStream::VIDEO);
if (!audio_stream || !video_stream ||
!audio_stream->audio_decoder_config().IsValidConfig() ||
!video_stream->video_decoder_config().IsValidConfig()) {
error_occurred_ = true;
return;
}
audio_stream->Read(BindToCurrentLoop(Bind(
&ShellDemuxerFuzzer::ReadCB, base::Unretained(this), audio_stream)));
video_stream->Read(BindToCurrentLoop(Bind(
&ShellDemuxerFuzzer::ReadCB, base::Unretained(this), video_stream)));
}
void StopCB() { stopped_ = true; }
void ReadCB(const scoped_refptr<DemuxerStream>& stream,
DemuxerStream::Status status,
const scoped_refptr<DecoderBuffer>& buffer) {
DCHECK_NE(status, DemuxerStream::kAborted);
if (status == DemuxerStream::kOk) {
DCHECK(buffer);
if (buffer->IsEndOfStream()) {
++eos_count_;
return;
}
}
DCHECK(!error_occurred_);
stream->Read(BindToCurrentLoop(
Bind(&ShellDemuxerFuzzer::ReadCB, base::Unretained(this), stream)));
}
bool error_occurred_;
int eos_count_;
bool stopped_;
scoped_refptr<ShellDemuxer> demuxer_;
};
class ShellDemuxerFuzzerApp : public FuzzerApp {
public:
explicit ShellDemuxerFuzzerApp(MediaSandbox* media_sandbox)
: media_sandbox_(media_sandbox) {}
std::vector<uint8> ParseFileContent(
const std::string& file_name,
const std::vector<uint8>& file_content) OVERRIDE {
std::string ext = FilePath(file_name).Extension();
if (ext != ".flv" && ext != ".mp4") {
LOG(ERROR) << "Skip unsupported file " << file_name;
return std::vector<uint8>();
}
return file_content;
}
void Fuzz(const std::string& file_name,
const std::vector<uint8>& fuzzing_content) OVERRIDE {
ShellDemuxerFuzzer demuxer_fuzzer(fuzzing_content);
demuxer_fuzzer.Fuzz();
}
private:
MediaSandbox* media_sandbox_;
};
int SandboxMain(int argc, char** argv) {
MediaSandbox media_sandbox(
argc, argv, FilePath(FILE_PATH_LITERAL("shell_demuxer_fuzzer.json")));
ShellDemuxerFuzzerApp fuzzer_app(&media_sandbox);
if (fuzzer_app.Init(argc, argv)) {
fuzzer_app.RunFuzzingLoop();
}
return 0;
}
} // namespace
} // namespace sandbox
} // namespace media
} // namespace cobalt
COBALT_WRAP_SIMPLE_MAIN(cobalt::media::sandbox::SandboxMain);